This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115c. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-09-25


1414. Binding an rvalue reference to a reference-unrelated lvalue

Section: 9.4.4  [dcl.init.ref]     Status: drafting     Submitter: Mike Miller     Date: 2011-11-09

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:

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.

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
    }

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:

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