This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 119a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-12-20
[Voted into the WP at the November, 2010 meeting.]
N3092 comment US 48The requirement that an rvalue reference must be bound to an rvalueis found in 9.5.4 [dcl.init.ref] bullet 5.2:
Otherwise, the reference shall be an lvaluereference to a non-volatile const type (i.e.,cv1 shall beconst), or the reference shall be an rvalue reference andthe initializer expression shall be an rvalue or have afunction type.
This is not quite correct, as it is phrased in terms of the valuecategory of the initializer expression itself rather than that ofthe result of any conversions applied to the initializer. It shouldbe permitted to bind an rvalue reference to a temporary created froman lvalue, for instance, or to the rvalue result of a conversionfunction for an lvalue object of class type. Also, it shouldnotbe permitted to bind an rvalue reference to the lvalue result of aconversion function for a class rvalue.
Proposed resolution (August, 2010):
Change 9.5.4 [dcl.init.ref] paragraph 5 as follows:
A reference to type “cv1T1”is initialized by an expression of type “cv2T2” as follows:
If the reference is an lvalue reference and theinitializer expression
is an lvalue (but is not a bit-field), and“cv1T1” is reference-compatiblewith “cv2T2,” or
has a class type (i.e.,T2 is a class type),whereT1 is not reference-related toT2,and can be implicitly converted to an lvalue of type“cv3T3,” where“cv1T1” is reference-compatiblewith “cv3T3”105(this conversion is selected by enumerating the applicableconversion functions (12.2.2.7 [over.match.ref]) andchoosing the best one through overload resolution(12.2 [over.match])),
then the reference is bound to the initializer expressionlvalue in the first case and to the lvalue result of theconversion in the second case (or, in either case, to theappropriate base class subobject of the object).[Note: the usual lvalue-to-rvalue (7.3.2 [conv.lval]), array-to-pointer (7.3.3 [conv.array]),and function-to-pointer (7.3.4 [conv.func]) standardconversions are not needed, and therefore are suppressed,when such direct bindings to lvalues are done. —endnote]
[Example:
double d = 2.0; double& rd = d; //rd refers tod const double& rcd = d; //rcd refers tod struct A { }; struct B : A {operator int&(); } b; A& ra = b; //ra refers toA subobject inb const A& rca = b; //rca refers toA subobject inb int& ir = B(); //ir refers to the result ofB::operator int&—end example]
Otherwise, the reference shall be an lvalue referenceto a non-volatile const type (i.e.,cv1 shall beconst), or the reference shall be an rvaluereference
and the initializer expression shall be an rvalueor have a function type. [Example:double& rd2 = 2.0; // error: not an lvalue and reference notconst int i = 2; double& rd3 = i; // error: type mismatch and reference notconstdouble&& rd4 = i; // error: rvalue reference cannot bind to lvalue—end example]
If the initializer expression
is an xvalue, class prvalue, array prvalue orfunction lvalue and “cv1T1” isreference-compatible with “cv2T2”, or
has a class type (i.e.,T2 is a class type),whereT1 is not reference-related toT2,and can be implicitly converted to an xvalue, class prvalue,or function lvalue of type “cv3T3,” where “cv1T1” is reference-compatible with“cv3T3”,
then the reference is bound to the value of theinitializer expression in the first case and to the resultof the conversion in the second case (or, in either case, toan appropriate base class subobject). In the second case, ifthe reference is an rvalue reference and the second standardconversion sequence of the user-defined conversion sequenceincludes an lvalue-to-rvalue conversion, the program isill-formed.
IfT1 is a function type, then
ifT2 is the same type asT1,the reference is bound to the initializer expressionlvalue;
ifT2 is a class type and the initializerexpression can be implicitly converted to an lvalue of typeT1 (this conversion is selected by enumerating theapplicable conversion functions (12.2.2.7 [over.match.ref]) and choosing the best one through overloadresolution (12.2 [over.match])), the reference isbound to the function lvalue that is the result of theconversion;
otherwise, the program is ill-formed.
Otherwise, ifT2 is a class type and
the initializer expression is an rvalue and“cv1T1” is reference-compatiblewith “cv2T2”, or
T1 is not reference-related toT2and the initializer expression can be implicitly convertedto an rvalue of type “cv3T3”(this conversion is selected by enumerating the applicableconversion functions (12.2.2.7 [over.match.ref]) andchoosing the best one through overload resolution(12.2 [over.match])),
then the reference is bound to the initializer expressionrvalue in the first case and to the object that is theresult of the conversion in the second case (or, in eithercase, to the appropriate base class subobject of theobject).[Example:
struct A { }; struct B : A { } b; extern B f(); const A& rca = f(); // bound to theA subobject of theB rvalue. A&&rcbrra = f(); // same as above struct X { operator B(); operator int&(); } x; const A& r = x; // bound to theA subobject of the result of the conversion int&& rri = static_cast<int&&>(i); // bound directly toi B&& rrb = x; // bound directly to the result ofoperator B int&& rri2 = X(); // error: lvalue-to-rvalue conversion applied to result ofoperator int&—end example]
If the initializer expression is an rvalue, withT2 an array type, and “cv1T1” is reference-compatible with“cv2T2,” the reference is boundto the object represented by the rvalue (see 7.2.1 [basic.lval]).Otherwise, a temporary of type “cv1T1” is created and initialized from theinitializer expression using the rules for a non-referencecopy-initialization (9.5 [dcl.init]). Thereference is then bound to the temporary. IfT1 isreference-related toT2,cv1
mustshall be the same cv-qualification as, or greatercv-qualification than,cv2; otherwise, theprogram is ill-formed.IfT1 isreference-related toT2 and the reference is anrvalue reference, the initializer expression shall not be anlvalue. [Example:const double& rcd2 = 2; //rcd2 refers to temporary with value2.0 double&&rcd3rrd = 2; //rcd3rrd refers to temporary with value2.0 const volatile int cvi = 1; const int& r = cvi; // error: type qualifiers dropped double&& rrd2 = d; // error: copying lvalue of related type double&& rrd3 = i; //rrd3 refers to temporary with value2.0—end example]
In all cases except the last (i.e., creating andinitializing a temporary from the initializer expression),the reference is said tobind directly to theinitializer expression.
This resolution also resolvesissue 1139.