Can we const-cast a non-class prvalue to xvalue?
Asked Answered
L

0

6

Consider this example from 7.6.1.10, paragraph 3 [expr.const.cast] (N4810):

typedef int *A[3]; // array of 3 pointer to int
typedef const int *const CA[3]; // array of 3 const pointer to const int
...
A &&r2 = const_cast<A&&>(CA{}); // OK

So, the standard says it's a legitimate code, but

  • none of g++-7 or clang-6 compiles fine.

  • In fact, this const_cast-related comments from llvm states:

    ....
    
    if (isa<RValueReferenceType>(DestTypeTmp) && SrcExpr.get()->isRValue()) {
        if (!SrcType->isRecordType()) {
            // Cannot const_cast non-class prvalue to rvalue reference type. But if
            // this is C-style, static_cast can do this.
            msg = diag::err_bad_cxx_cast_rvalue;
            return TC_NotApplicable;
        }
    
        // Materialize the class prvalue so that the const_cast can bind a
        // reference to it.
        NeedToMaterializeTemporary = true;
    }
    
    ...
    

    This basically says that we can't materialize(=cast) a non-class prvalue to a xvalue.

  • Also, the same paragraph from which the above example originates says:

    For two similar types T1 and T2, a prvalue of type T1 may be explicitly converted to the type T2 using a const_cast. The result of a const_cast refers to the original entity.

    Compare this to the one right after it (7.6.1.10, paragraph 4 [expr.const.cast]):

    For two object types T1 and T2, if a pointer to T1 can be explicitly converted to the type “pointer to T2” using a const_cast, then the following conversions can also be made:

    • an lvalue of type T1 can be explicitly converted to an lvalue of type T2 using the cast const_cast<T2&>;
    • a glvalue of type T1 can be explicitly converted to an xvalue of type T2 using the cast const_cast<T2&&>; and
    • if T1 is a class type, a prvalue of type T1 can be explicitly converted to an xvalue of type T2 using the cast const_cast<T2&&>.

    The result of a reference const_cast refers to the original object if the operand is a glvalue and to the result of applying the temporary materialization conversion otherwise.

    This contrast seems to insinuate that, a cast from a non-class prvalue to a xvalue won't suffer temporary materialization conversion, which looks odd to me.

Then, what's the intention of the example above?

Lamp answered 3/5, 2019 at 1:59 Comment(9)
wg21.link/cwg1965Tryck
The result of a const_cast refers to the original entity This wording is clearly defective, because in C++17 and above prvalues do not denote entities.Tryck
@LanguageLawyer So, the above example is defective. Thanks.Lamp
@LanguageLawyer The wording is not defective. The wording you quoted is in paragraph 3, and doesn't apply to the reference case, which is paragraph 4. The wording in paragraph 4 makes it clear that the result only refers to the original object if the operand is a glvalue.Mog
@Brian the first and the second sentence in paragraph 3 are not related?Tryck
@LanguageLawyer They are. The second sentence in paragraph 3 is related to the first sentence in paragraph 3. Paragraph 3 does not apply to the case where the destination type is a reference, because a reference type can never be similar to the non-reference type of the operand.Mog
@Brian Paragraph 3 does not apply to the case where the destination type is a reference But I didn't mean this. I just told that in C++17 and above prvalues can't denote objects, so one can't "refer to the original entity".Tryck
@LanguageLawyer Ah, I see what you mean now. I suppose the wording does need improvement. I think it was meant to denote cases like casting const int* to int*, where the resulting value points to the same entity as the original value.Mog
@Brian Although, [basic.lval]/2 says A prvalue whose result is the value V is sometimes said to have or name the value V, so it can be said that a prvalue denotes entity (value).Tryck

© 2022 - 2024 — McMap. All rights reserved.