c++language-lawyerconst-cast

Const cast to non-pointer non-reference type


From [expr.const.cast]/3:

For two similar types T1 and T2, a prvalue of type T1 may be explicitly converted to the type T2 using a const_­cast if, considering the cv-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.

It seems that const cast to non-pointer non-reference type is allowed. For example, the following function

void f(int a)
{
    const_cast<int>(a);
}

should be well-formed, since int and int are certainly similar types and have no Pi in their cv-decompositions (thus the proposition that "each Pi1 is the same as Pi2 for all i" should be true).

However, both GCC and Clang reject the code above (see Compiler Explorer). The error messages are

Clang:

<source>: In function 'void f(int)':
<source>:3:22: error: invalid use of const_cast with type 'int', which is not a pointer, reference, nor a pointer-to-data-member type
    3 |     const_cast<int>(a);
      |                      ^

GCC:

<source>: In function 'void f(int)':
<source>:3:5: error: invalid use of 'const_cast' with type 'int', which is not a pointer, reference, nor a pointer-to-data-member type
    3 |     const_cast<int>(a);
      |     ^~~~~~~~~~~~~~~~~~

Am I missing something or is it a compiler bug?

UPDATE: this doesn't work, either:

void f()
{
    const_cast<int>(int{});
}

Solution

  • In C++17 the types are not similar so the quoted text doesn't apply. And so this const_cast is not allowed because no const_cast is allowed unless explicitly permitted.

    C++17 [conv.qual]/1:

    A cv-decomposition of a type T is a sequence of cvi and Pi such that T is

    “cv0 P0 cv1 P1 ··· cvn-1 Pn-1 cvn Ufor n > 0,

    where each cvi is a set of cv-qualifiers (6.9.3), and each Pi is “pointer to” (11.3.1), “pointer to member of class Ci of type” (11.3.3), “array of Ni ”, or “array of unknown bound of” (11.3.4). [...]

    and then

    Two types T1 and T2 are similar if they have cv-decompositions with the same n such that corresponding Pi components are the same and the types denoted by U are the same.

    The requirement n > 0 means that there must be cv0 P0, i.e. at least one pointer in the type.


    The latest C++20 draft changes n > 0 to n ≥ 0, as a result of Issue 2051. But makes no change to the specification of const_cast. I couldn't say whether this is intentional or an oversight.

    So it may be that C++20 will make your const_cast expressions well-defined , and compilers will have to catch up.