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
[Voted into WP at October, 2009 meeting.]
Consider the following example:
struct A { }; struct B : public A { }; struct X { operator B(); }; X x; int main() { const A& r = x; return 0; }
It seems like the resolution of issue 391 doesn't actually cover this; X is not reference-compatible with A, so we go past the modified bullet (9.4.4 [dcl.init.ref] paragraph 5, bullet 2, sub-bullet 1), which reads:
If the initializer expression is an rvalue, with T2 a class 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]) or to a sub-object within that object.
and hit
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.4 [dcl.init]). The reference is then bound to the temporary.
which seems to require that we create an A temporary copied from the return value of X::operator B() rather than bind directly to the A subobject. I think that the resolution of issue 391 should cover this situation as well, and the EDG compiler seems to agree with me.
(See also issue 896.)
Proposed resolution (September, 2009):
Change 9.4.4 [dcl.init.ref] paragraph 5 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 rvalue, with
T2 a class 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]) or to a sub-object within that
object. If T1 and T2 are class types
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,” where “cv1 T1” is reference-compatible with “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). [Example:
struct A { }; struct B : A { } b; extern B f(); const A& rca = f(); // Bound to the A subobject of the B rvalue. A&& rcb = f(); // Same as above struct X { operator B(); } x; const A& r = x; // Bound to the A subobject of the result of the conversion
—end example]
...
Editorial note: issue 589 makes edits to the top-level bullet preceding this one. The wording resulting from those edits should be changed for consistency with this wording so that the text there reads, “...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).”
Change 12.2 [over.match] paragraph 2, last bullet as follows:
Change 12.2.2.7 [over.match.ref] paragraph 1 as follows:
Under the conditions specified in 9.4.4 [dcl.init.ref], a reference can be bound directly to an lvalue or class rvalue that is the result of applying a conversion function to an initializer expression. Overload resolution is used to select the conversion function to be invoked. Assuming that “cv1 T” is the underlying type of the reference being initialized, and “cv S” is the type of the initializer expression, with S a class type, the candidate functions are selected as follows:
The conversion functions of S and its base classes are considered, except that for copy-initialization, only the non-explicit conversion functions are considered. Those that are not hidden within S and yield type “lvalue reference to cv2 T2” (when 9.4.4 [dcl.init.ref] requires an lvalue result), or “cv2 T2” or “rvalue reference to cv2 T2 (when 9.4.4 [dcl.init.ref] requires an rvalue result), where “cv1 T” is reference-compatible (9.4.4 [dcl.init.ref]) with “cv2 T2”, are candidate functions.
(Note: this resolution also resolves issue 896.)