This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-10-26
[Moved to DR at the November, 2014 meeting.]
In the case of indirect reference binding, 9.4.4 [dcl.init.ref] paragraph 5 only requires that the cv-qualification of the referred-to type be the same or greater than that of the initializer expression when the types are reference-related. This leads to the following anomaly:
class A { public: operator volatile int &(); }; A a; const int & ir1a = a.operator volatile int&(); // error! const int & ir2a = a; // allowed! ir = a.operator volatile int&();
Is this intended?
Notes from the April, 2013 meeting:
CWG felt that the declaration of ir2a should also be an error.
Proposed resolution (February, 2014):
Change 9.4.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...
Otherwise, the reference shall be an lvalue reference to a non-volatile const type...
If the initializer expression
is an xvalue (but not a bit-field), 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 converted to an xvalue, class prvalue, or function lvalue of type “cv3 T3”, where “cv1 T1” is reference-compatible with “cv3 T3” (see 12.2.2.7 [over.match.ref]),
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:struct A { }; struct B : A { } b; extern B f(); const A& rca2 = f(); // bound to the A subobject of the B rvalue. A&& 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 i2 = 42; int&& rri = static_cast<int&&>(i2); // bound directly to i2 B&& rrb = x; // bound directly to the result of operator Bint&& rri2 = X(); // error: lvalue-to-rvalue conversion applied to the // result of operator int&—end example]
Otherwise:
If T1 or T2 is a class type and T1 is not reference-related to T2, user-defined conversions are considered using the rules for copy-initialization of an object of type “cv1 T1” by user-defined conversion (9.4 [dcl.init], 12.2.2.5 [over.match.copy], 12.2.2.6 [over.match.conv]); the program is ill-formed if the corresponding non-reference copy-initialization would be ill-formed. The result of the call to the conversion function, as described for the non-reference copy-initialization, is then used to direct-initialize the reference.
The program is ill-formed if the direct-initialization does not result in a direct binding or if it involves a user-defined conversion.For this direct-initialization, user-defined conversions are not considered.
If T1 is a non-class typeOtherwise, a temporary of type “cv1 T1” is created and copy-initialized (9.4 [dcl.init]) from the initializer expression. The reference is then bound to the temporary.If T1 is reference-related to T2:
cv1 shall be the same cv-qualification as, or greater cv-qualification than, cv2; and
if the reference is an rvalue reference, the initializer expression shall not be an lvalue.
[Example:
struct Banana { }; struct Enigma { operator const Banana(); }; struct Alaska { operator Banana&(); }; void enigmatic() { typedef const Banana ConstBanana; Banana &&banana1 = ConstBanana(); // ill-formed Banana &&banana2 = Enigma(); // ill-formed Banana &&banana2 = Alaska(); // ill-formed } const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0 double&& rrd = 2; // rrd refers to temporary with value 2.0 const volatile int cvi = 1; const int& r2 = cvi; // error: type qualifiers dropped struct A { operator volatile int&(); } a; const int& r3 = a; // error: type qualifiers dropped from result of conversion function double d2 = 1.0; double&& rrd2 = d2; // error:copyinginitializer is lvalue of related type struct X { operator int&(); }; int && rri2 = X(); // error: result of conversion function is lvalue of related type int i3 = 2; double&& rrd3 = i3; // rrd3 refers to temporary with value 2.0—end example]
This resolution also resolves issue 1572.