This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 117a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-04-13
[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.5.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.5 [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.5.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.5.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.5.4 [dcl.init.ref] requires an lvalue result), or βcv2 T2β or βrvalue reference to cv2 T2 (when 9.5.4 [dcl.init.ref] requires an rvalue result), where βcv1 Tβ is reference-compatible (9.5.4 [dcl.init.ref]) with βcv2 T2β, are candidate functions.
(Note: this resolution also resolves issue 896.)