Search code examples
c++language-lawyervalue-categories

Is it legal to cast a non-class non-array prvalue to a cv-qualified type?


I was reading up on value categories, and came across the following (much omitted for brevity):

The following expressions are prvalue expressions:

  • a literal (except for string literal), such as 42, true or nullptr;

Properties:

  • A non-class non-array prvalue cannot be cv-qualified.

But ... the following program compiles and runs fine on ideone.com and with g++ 5.4.0:

#include <iostream>

int main() {
    std::cout << ((const int) 42) << std::endl;
}

I understand that compilers provide extensions, and can do all manner of things if undefined behaviour is hit. I am simply trying to work out what the standard mandates.

In N4296, I found the following to relevant passage:

[expr]

[ ... content omitted ... ]

  1. If a prvalue initially has the type “ cv T ,” where T is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T prior to any further analysis.

The term "initially" is what throws me. It's not clear if this is allowed as the result of another expression, such as the user to explicitly casting a non-class non-array prvalue to a cv-qualified type (which yields another prvalue), or whether this applies only the "root" expression (42 in this case).

My question is, does the standard allow such expressions (which just strips away the cv-qualifiers), or is this disallowed (and if relevant, where is this mandated)?


Solution

  • Thanks to SanderDeDycker for pointing out the relevant part of the standard to search in.

    My question is answered in the following section of N4296 (emphasis mine):

    [expr.cast]

    1. The result of the expression (T) cast-expression is of type T . The result is an lvalue if T is an lvalue reference type or an rvalue reference to function type and an xvalue if T is an rvalue reference to object type; otherwise the result is a prvalue. [ Note: if T is a non-class type that is cv-qualified, the cv-qualifiers are discarded when determining the type of the resulting prvalue; see Clause 5. — end note ]

    So we can conclude that expressions such as (const int) 42 are perfectly legal C++.