Title
Binding an rvalue reference to a reference-unrelated lvalue
Status
drafting
Section
9.4.4 [dcl.init.ref]
Submitter
Mike Miller

Created on 2011-11-09.00:00:00 last changed 139 months ago

Messages

Date: 2012-10-15.00:00:00

Additional note (October, 2012):

Removing “to an rvalue,” as suggested, would have the effect of negating the preference for binding a function lvalue to an lvalue reference instead of an rvalue reference because the case would now fall under the preceding bullet of 12.2.4.3 [over.ics.rank] bullet 3.1, sub-bullets 4 and 5:

Two implicit conversion sequences of the same form are indistinguishable conversion sequences unless one of the following rules applies:

  • Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if

    • ...

    • S1 and S2 are reference bindings (9.4.4 [dcl.init.ref]) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, and S1 binds an rvalue reference to an rvalue and S2 binds an lvalue reference... or, if not that,

    • S1 and S2 are reference bindings (9.4.4 [dcl.init.ref]) and S1 binds an lvalue reference to a function lvalue and S2 binds an rvalue reference to a function lvalue.

Presumably if the suggested resolution is adopted, the order of these two bullets should be inverted.

Date: 2012-02-15.00:00:00

Notes from the February, 2012 meeting:

CWG agreed that the binding rules are correct, allowing creation of a temporary when binding an rvalue reference to a non-reference-related lvalue. The phrase “to an rvalue” in 12.2.4.3 [over.ics.rank] paragraph 3 is a leftover from before binding an rvalue reference to an lvalue was prohibited and should be removed. A change is also needed to handle the following case:

    void f(const char (&)[1]);         // #1
    template<typename T> void f(T&&);  // #2
    void g() {
      f("");                           //calls #2, should call #1
    }
Date: 2011-11-09.00:00:00

Currently an attempt to bind an rvalue reference to a reference-unrelated lvalue succeeds, binding the reference to a temporary initialized from the lvalue by copy-initialization. This appears to be intentional, as the accompanying example contains the lines

    int i3 = 2;
    double&& rrd3 = i3;  // rrd3 refers to temporary with value 2.0

This violates the expectations of some who expect that rvalue references can be initialized only with rvalues. On the other hand, it is parallel with the handling of an lvalue reference-to-const (and is handled by the same wording). It also can add efficiency without requiring existing code to be rewritten: the implicitly-created temporary can be moved from, just as if the call had been rewritten to create a prvalue temporary from the lvalue explicitly.

On a related note, assuming the binding is permitted, the intent of the overload tiebreaker found in 12.2.4.3 [over.ics.rank] paragraph 3 is not clear:

  • Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if

    • ...

    • S1 and S2 are reference bindings (9.4.4 [dcl.init.ref]) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, and S1 binds an rvalue reference to an rvalue and S2 binds an lvalue reference.

At question is what “to an rvalue” means here. If it is referring to the value category of the initializer itself, before conversions, then the supposed performance advantage of the binding under discussion does not occur because the competing rvalue and lvalue reference overloads will be ambiguous:

    void f(int&&);    // #1
    void f(const int&);
    void g(double d) {
        f(d);         // ambiguous: #1 does not bind to an rvalue
    }

On the other hand, if “to an rvalue” refers to the actual object to which the reference is bound, i.e., to the temporary in the case under discussion, the phrase would seem to be vacuous because an rvalue reference can never bind directly to an lvalue.

History
Date User Action Args
2012-11-03 00:00:00adminsetmessages: + msg4094
2012-02-27 00:00:00adminsetmessages: + msg3769
2012-02-27 00:00:00adminsetstatus: open -> drafting
2011-11-09 00:00:00admincreate