Title
Direct binding to the result of a conversion operator
Status
cd2
Section
9.4.4 [dcl.init.ref]
Submitter
Jason Merrill

Created on 2007-10-23.00:00:00 last changed 143 months ago

Messages

Date: 2009-10-15.00:00:00

[Voted into WP at October, 2009 meeting.]

Date: 2009-09-15.00:00:00

Proposed resolution (September, 2009):

  1. 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).”

  2. Change 12.2 [over.match] paragraph 2, last bullet as follows:

    • invocation of a conversion function for conversion to an lvalue or class rvalue to which a reference (9.4.4 [dcl.init.ref]) will be directly bound (12.2.2.7 [over.match.ref]).
  3. Change 12.2.2.7 [over.match.ref] paragraph 1 as follows:

  4. 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.)

Date: 2009-08-03.00:00:00

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.)

History
Date User Action Args
2010-03-29 00:00:00adminsetstatus: dr -> cd2
2009-11-08 00:00:00adminsetmessages: + msg2460
2009-11-08 00:00:00adminsetstatus: tentatively ready -> dr
2009-09-29 00:00:00adminsetmessages: + msg2299
2009-09-29 00:00:00adminsetstatus: drafting -> tentatively ready
2009-08-03 00:00:00adminsetstatus: open -> drafting
2007-10-23 00:00:00admincreate