[Voted into the WP at the November, 2010 meeting.]
Proposed resolution (August, 2010): Change 9.5.4 [dcl.init.ref] paragraph 5 as follows: A reference to type “cv1 T1 ”
is initialized by an expression of type “cv2
T2 ” as follows: If the reference is an lvalue reference and the
initializer expression is an lvalue (but is not a bit-field), and
“cv1 T1 ” is reference-compatible
with “cv2 T2 ,” or has a class type (i.e., T2 is a class type),
where T1 is not reference-related to T2 ,
and can be implicitly converted to an lvalue of type
“cv3 T3 ,” where
“cv1 T1 ” is reference-compatible
with “cv3 T3 ”105
(this conversion is selected by enumerating the applicable
conversion functions (12.2.2.7 [over.match.ref]) and
choosing the best one through overload resolution
(12.2 [over.match])), then the reference is bound to the initializer expression
lvalue in the first case and to the lvalue result of the
conversion in the second case (or, in either case, to the
appropriate 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]) standard
conversions are not needed, and therefore are suppressed,
when such direct bindings to lvalues are done. —end
note] [Example:
—end example] Otherwise, the reference shall be an lvalue reference
to a non-volatile const type (i.e., cv1 shall be
const ), or the reference shall be an rvalue
reference —end example] If the initializer expression is an xvalue, class prvalue, array prvalue or
function lvalue and “cv1 T1 ” is
reference-compatible with “cv2
T2 ”, or has a class type (i.e., T2 is a class type),
where T1 is not reference-related to T2 ,
and can be implicitly converted to an xvalue, class prvalue,
or function lvalue of type “cv3
T3 ,” where “cv1
T1 ” is reference-compatible with
“cv3 T3 ”, then the reference is bound to the value of the
initializer expression in the first case and to the result
of the conversion in the second case (or, in either case, to
an appropriate base class subobject). In the second case, if
the reference is an rvalue reference and the second standard
conversion sequence of the user-defined conversion sequence
includes an lvalue-to-rvalue conversion, the program is
ill-formed. [Example:
—end example] Otherwise, a temporary of type “cv1
T1 ” is created and initialized from the
initializer expression using the rules for a non-reference
copy-initialization (9.5 [dcl.init]). The
reference is then bound to the temporary. If T1 is
reference-related to T2 , cv1 —end example] In all cases except the last (i.e., creating and
initializing a temporary from the initializer expression),
the reference is said to bind directly to the
initializer expression. This resolution also resolves issue 1139.
double d = 2.0;
double& rd = d; // rd refers to d
const double& rcd = d; // rcd refers to d
struct A { };
struct B : A { operator int&(); } b;
A& ra = b; // ra refers to A subobject in b
const A& rca = b; // rca refers to A subobject in b
int& ir = B(); // ir refers to the result of B::operator int&
and the initializer expression shall be an rvalue
or have a function type. [Example:
double& rd2 = 2.0; // error: not an lvalue and reference not const
int i = 2;
double& rd3 = i; // error: type mismatch and reference not const
double&& rd4 = i; // error: rvalue reference cannot bind to lvalue
If T1 is a function type, then
if T2 is the same type as T1 ,
the reference is bound to the initializer expression
lvalue;if T2 is a class type and the initializer
expression can be implicitly converted to an lvalue of type
T1 (this conversion is selected by enumerating the
applicable conversion functions (12.2.2.7 [over.match.ref]) and choosing the best one through overload
resolution (12.2 [over.match])), the reference is
bound to the function lvalue that is the result of the
conversion;otherwise, the program is ill-formed.Otherwise, if T2 is a class type and
the initializer expression is an rvalue and
“cv1 T1 ” is reference-compatible
with “cv2 T2 ”, or T1 is not reference-related to T2
and the initializer expression can be implicitly converted
to an rvalue of type “cv3 T3 ”
(this conversion is selected by enumerating the applicable
conversion functions (12.2.2.7 [over.match.ref]) and
choosing the best one through overload resolution
(12.2 [over.match])),then the reference is bound to the initializer expression
rvalue in the first case and to the object that is the
result of the conversion in the second case (or, in either
case, to the appropriate base class subobject of the
object).
struct A { };
struct B : A { } b;
extern B f();
const A& rca = f(); // bound to the A subobject of the B rvalue.
A&&
rcb rra = f(); // same as above
struct X {
operator B();
operator int&();
} x;
const A& r = x; // bound to the A subobject of the result of the conversion
int&& rri = static_cast<int&&>(i); // bound directly to i
B&& rrb = x; // bound directly to the result of operator B
int&& rri2 = X(); // error: lvalue-to-rvalue conversion applied to result of operator int&
If the initializer expression is an rvalue, with
T2 an array type, and “cv1
T1 ” is reference-compatible with
“cv2 T2 ,” the reference is bound
to the object represented by the rvalue (see 7.2.1 [basic.lval]).must
shall be the same cv-qualification as, or greater
cv-qualification than, cv2; otherwise, the
program is ill-formed. If T1 is
reference-related to T2 and the reference is an
rvalue reference, the initializer expression shall not be an
lvalue. [Example:
const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0
double&&
rcd3 rrd = 2; // rcd3 rrd refers to temporary with value 2.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 value 2.0
N3092 comment
US 48 The requirement that an rvalue reference must be bound to an rvalue
is found in 9.5.4 [dcl.init.ref] bullet 5.2: Otherwise, the reference shall be an lvalue
reference to a non-volatile const type (i.e., cv1 shall be
const ), or the reference shall be an rvalue reference and
the initializer expression shall be an rvalue or have a
function type. This is not quite correct, as it is phrased in terms of the value
category of the initializer expression itself rather than that of
the result of any conversions applied to the initializer. It should
be permitted to bind an rvalue reference to a temporary created from
an lvalue, for instance, or to the rvalue result of a conversion
function for an lvalue object of class type. Also, it should not
be permitted to bind an rvalue reference to the lvalue result of a
conversion function for a class rvalue.
N3092 comment
GB 37
N3092 comment
DE 10