Proposed resolution (approved by CWG 2024-10-25)
Change in 7.2.1 [basic.lval] paragraph 7 as follows:
WheneverUnless otherwise specified (7.6.1.11 [expr.const.cast]), whenever a prvalue appears as an operand of an operator that expects a glvalue for that operand, the temporary materialization conversion (7.3.5 [conv.rval]) is applied to convert the expression to an xvalue.
Change in 7.6.1.11 [expr.const.cast] paragraph 1 as follows:
The result of the expression const_cast<T>(v) is of type T. If T is an lvalue reference to object type, the result is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue and the 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 performed on the expression v. The temporary materialization conversion (7.3.5 [conv.rval]) is not performed on v, other than as specified below. Conversions that can be performed explicitly using const_cast are listed below. No other conversion shall be performed explicitly using const_cast.
Change in 7.6.1.11 [expr.const.cast] paragraph 3 as follows:
For two similar object pointer or pointer to data member types T1 and T2 (7.3.6 [conv.qual]), a prvalue of type T1maycan be explicitly converted to the type T2 using a const_cast if, considering the qualification-decompositions of both types, each Pi1 is the same as Pi2 for all i.The result of a const_cast refers to the original entity.If v is a null pointer or null member pointer, the result is a null pointer or null member pointer, respectively. Otherwise, the result points to or past the end of the same object, or points to the same member, respectively, as v.[Example 1:typedef int *A[3]; // array of 3 pointer to int typedef const int *const CA[3]; // array of 3 const pointer to const int CA &&r = A{}; // OK, reference binds to temporary array object // after qualification conversion to type CA A &&r1 = const_cast<A>(CA{}); // error: temporary array decayed to pointer A &&r2 = const_cast<A&&>(CA{}); // OK-- end example]
Change in 7.6.1.11 [expr.const.cast] paragraph 4 as follows:
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:The result
- 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 or array type, a prvalue of type T1 can be explicitly converted to an xvalue of type T2 using the cast const_cast<T2&&>. The temporary materialization conversion is performed on v.
of a reference const_castrefers to theoriginalsame objectifas the (possibly converted) operandis a glvalue and to the result of applying the temporary materialization conversion (7.3.5 [conv.rval]) otherwise.[Example 2:
typedef int *A[3]; // array of 3 pointer to int typedef const int *const CA[3]; // array of 3 const pointer to const int auto &&r2 = const_cast<A&&>(CA{}); // OK, temporary materialization conversion is performed-- end example]
Remove 7.6.1.11 [expr.const.cast] paragraph 5:
A null pointer value (6.8.4 [basic.compound]) is converted to the null pointer value of the destination type. The null member pointer value (7.3.13 [conv.mem]) is converted to the null member pointer value of the destination type.
Change in 9.5.4 [dcl.init.ref] bullet 5.3 as follows:
[Example 5: ...constexpr int f() { const int &x = 42; const_cast<int &>(x) = 1; // undefined behavior return x; } constexpr int z = f(); // error: not a constant expressiontypedef int *AP[3]; // array of 3 pointer to int typedef const int *const ACPC[3]; // array of 3 const pointer to const int ACPC &&r = AP{}; // binds directly-- end example]
This resolution also resolve issue 1965.