Skip to content

CWG2894 [expr.type.conv] T{...} Functional casts create prvalues of reference type T #536

Closed
cplusplus/draft
#7458
@Eisenwave

Description

@Eisenwave

Reference: [expr.type.conv] paragraph 2, sentence 3

Issue description

In T{...}, if T is a reference type, [expr.type.conv] paragraph 2, sentence 3 applies, stating:

Otherwise, the expression is a prvalue of the specified type whose result object is direct-initialized with the initializer.

This is defective for references; there can be no prvalues of reference type.

Furthermore, it is not sufficiently clear that void(1, 2) and void{1} are not valid. All compilers reject these forms, and should.

Suggested resolution

Update [expr.type.conv] paragraph 2 as follows:

Let T be the specified type. The effect of the expression is as follows:
  • If the initializer is a parenthesized single expression, the type conversion expression is equivalent to the corresponding cast expression.
  • Otherwise, if the type T is cv void and the initializer is the initializer shall be () or {} (after pack expansion, if any), and the expression is a prvalue of type void that performs no initialization.
  • Otherwise, the expression is a prvalue of the specified type whose result object is direct-initialized with the initializer has the same effect as direct-initializing an invented variable T t with the given initializer and then using t as the result of the expression. The result is an lvalue if the specified type T is an lvalue reference type or reference to function type, an xvalue if T is an rvalue reference to object type, and a prvalue otherwise. If the initializer is a parenthesized optional expression-list, the specified type shall not be an array type.

To [expr.type.conv] paragraph 2, append an example:

void f() {
    unsigned(-1);     // OK, equivalent to (int) -1
    unsigned{-1};     // ill-formed, narrowing conversion
    
    void{};           // OK, prvalue of type void
    void(1);          // OK, equivalent to (void) 1
    void{0};          // ill-formed
    void(1, 2);       // ill-formed
    int(1, 2);        // ill-formed
    
    struct S { S(int, int); };
    S a = S(1, 2);    // OK, S(1, 2) is a prvalue
    S b = S(a);       // OK, equivalent to S b = (S) a;
    
    using R = S&;
    R r = R(a);       // OK, equivalent to R r = (R) a;
    R q = R{a};       // OK, same
}

[Editor's note: The example is intended to be educational and highlight the cases void(1, 2), R{a}, which currently have wording issues or related compiler bugs.]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions