Title
Direct binding of class and array rvalues in reference initialization
Status
cd2
Section
9.4.4 [dcl.init.ref]
Submitter
Steve Adamczyk

Created on 2006-07-26.00:00:00 last changed 144 months ago

Messages

Date: 2009-10-15.00:00:00

[Voted into WP at October, 2009 meeting.]

Date: 2009-06-15.00:00:00

Proposed resolution (June, 2009):

  1. Change 9.4.4 [dcl.init.ref] paragraph 5 as follows:

  2. 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” (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 directly to the initializer expression lvalue in the first case, and the reference is bound and to the lvalue result of the conversion in the second case. In these cases the reference is said to bind directly to the initializer expression. [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 and the initializer expression shall be an rvalue. [Example: ... —end example]

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

        [Example: ... —end example]

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

      • 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. If T1 is reference-related to T2, cv1 must be the same cv-qualification as, or greater cv-qualification than, cv2; otherwise, the program is ill-formed. [Example: ... —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.

  3. Change 7.6.16 [expr.cond] paragraph 3 bullet 1 as follows:

    • If E2 is an lvalue: E1 can be converted to match E2 if E1 can be implicitly converted (Clause 7.3 [conv]) to the type “lvalue reference to T2”, subject to the constraint that in the conversion the reference must bind directly (9.4.4 [dcl.init.ref]) to E1 an lvalue.

Date: 2006-11-05.00:00:00

The resolutions of issues 391 and 450 say that the reference is “bound to” the class or array rvalue, but it does not say that the reference “binds directly” to the initializer, as it does for the cases that fall under the first bullet in 9.4.4 [dcl.init.ref] paragraph 5. However, this phrasing is important in determining the implicit conversion sequence for an argument passed to a parameter with reference type (12.2.4.2.5 [over.ics.ref]), where paragraph 2 says,

When a parameter of reference type is not bound directly to an argument expression, the conversion sequence is the one required to convert the argument expression to the underlying type of the reference according to 12.2.4.2 [over.best.ics]. Conceptually, this conversion sequence corresponds to copy-initializing a temporary of the underlying type with the argument expression.

The above-mentioned issue resolutions stated that no copy is to be made in such reference initializations, so the determination of the conversion sequence does not reflect the initialization semantics.

Simply using the “binds directly” terminology in the new wording may not be the right approach, however, as there are other places in the Standard that also give special treatment to directly-bound references. For example, the first bullet of 7.6.16 [expr.cond] paragraph 3 says,

If E2 is an lvalue: E1 can be converted to match E2 if E1 can be implicitly converted (clause 7.3 [conv]) to the type “reference to T2,” subject to the constraint that in the conversion the reference must bind directly (9.4.4 [dcl.init.ref]) to E1.

The effect of simply saying that a reference “binds directly” to a class rvalue can be seen in this example:

    struct B { };
    struct D: B { };
    D f();
    void g(bool x, const B& br) {
        x ? f() : br;   // result would be lvalue
    }

It is not clear that treating this conditional expression as an lvalue is a desirable outcome, even if the result of f() were to “bind directly” to the const B& reference.

History
Date User Action Args
2010-03-29 00:00:00adminsetstatus: dr -> cd2
2009-11-08 00:00:00adminsetmessages: + msg2459
2009-11-08 00:00:00adminsetstatus: ready -> dr
2009-08-03 00:00:00adminsetstatus: review -> ready
2009-06-19 00:00:00adminsetmessages: + msg2042
2009-06-19 00:00:00adminsetstatus: drafting -> review
2007-10-09 00:00:00adminsetstatus: open -> drafting
2006-07-26 00:00:00admincreate