The code below doesn't compile under GCC 5.3.0 because the declaration of r
is missing a constexpr
specifier.
const int i = 1;
const int& r = i;
constexpr int j = r;
I believe the rejection is correct. How do I prove it using the working draft N4527?
The keyword constexpr was introduced in C++11 and improved in C++14. It means constant expression. Like const , it can be applied to variables: A compiler error is raised when any code attempts to modify the value. Unlike const , constexpr can also be applied to functions and class constructors.
For example, constexpr variables and instances of user-defined types are automatically thread-safe and can be stored in ROM; constexpr functions that are evaluated at compile-time, are done with their work at run time.
First, since we're using a reference, [expr.const]/(2.9) must not be violated. (2.9.1) applies, though:
an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
— it is initialized with a constant expression
I.e. using r
is fine, as long as the initializer - i
- is a constant expression (this is shown below).
It's also necessary to check whether the l-t-r conversion in line 3 is legal, i.e. (2.7) must not be violated. However, (2.7.1) applies:
an lvalue-to-rvalue conversion (4.1) unless it is applied to
— a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatileconst
object with a preceding initialization, initialized with a constant expression, or
…so that's fine as well, since the (g)lvalue is r
, and it refers to i
- which is a non-volatile const
object with a constant expression initializer (1
).
We postponed showing that i
is actually a constant expression, and once that's out of the way, we need to show that r
is a constant expression.
[expr.const]/5 pertains to that:
A constant expression is either a glvalue core constant expression whose value refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value is an object where, for that object and its subobjects:
- each non-static data member of reference type refers to an entity that is a permitted result of a constant expression, and
- if the object or subobject is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object (5.7), the address of a function, or a null pointer value.
An entity is a permitted result of a constant expression if it is an object with static storage duration that is either not a temporary object or is a temporary object whose value satisfies the above constraints, or it is a function.
Since i
is, in the above context, a (g)lvalue, it has to be a permitted result of a constant expression - which it is, since it has static storage duration and certainly isn't a temporary. Thus i
is a constant expression.
r
is, however, treated as a prvalue in line 3. Since we already established that r
is a core constant expression, we solely need to check the bullet points. They're clearly met, though.
Hence the code is well-formed in namespace scope. It won't be in local scope, as i
wouldn't be a permitted result of a constant expression anymore. Clang gives a comprehensive error message.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With