int aaa;
int& v = aaa;
int& rf = v;
constexpr int& crf = rf;
int main(){
}
Why do all compilers agree that this example is well-formed? Shouldn't a constexpr variable have a value that can be known during compile time?
For this example, it appears to me it's equivalent to ask why the variable rf could be used in a constant expression. As per [dcl.constexpr#10], the full-expression of the initialization of crf should be a constant expression. According to [expr.const#11]
A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints
An entity is a permitted result of a constant expression if it is an object with static storage duration that either is not a temporary object or is a temporary object whose value satisfies the above constraints, or if it is a non-immediate function.
In this case, since the reference binding should be bound to a glvalue, hence rf shall be a glvalue core constant expression; Since rf refers to the object aaa that has a static storage duration, hence we only should check whether rf is core constant expression, which is determined by [expr.const#5]. Since rf is an id-expression of reference type, hence it shall satisfy [expr.const#5.12]
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 usable in constant expressions or
- its lifetime began within the evaluation of E;
Here it must satisfy that it is usable in a constant expression, which is determined by [expr.const#4]
A constant-initialized potentially-constant variable V is usable in constant expressions at a point P if V's initializing declaration D is reachable from P and
- V is constexpr,
- V is not initialized to a TU-local value, or
- P is in the same translation unit as D.
An object or reference is usable in constant expressions if it is
- a variable that is usable in constant expressions, or
Since rf is a reference, hence it is potentially-constant due to [expr.const#3]
A variable is potentially-constant if it is constexpr or it has reference or const-qualified integral or enumeration type.
Whether it is constant-initialized is determined by [expr.const#2]
A variable or temporary object o is constant-initialized if
- [2.1] either it has an initializer or its default-initialization results in some initialization being performed, and
- [2.2] the full-expression of its initialization is a constant expression when interpreted as a constant-expression...
The declaration of rf has an initializer, bullet 2.1 is true, as far as now, whether rf is a constant expression has turned to examine whether its full-expression of the initialization is a constant expression. Again, v shall be a constant expression; to judge whether v is a constant expression is similar to the process of rf as given in above. Which in turn is to judge whether the initializer aaa is a constant expression, I say yes, since aaa is a static storage duration object and evaluating it will not violate any rule defined in [expr.const#5], hence it's a glvalue core constant expression. Hence, v is usable in constant expression, which means rf is also usable in a constant expression. In short, the full-expression of the initialization of crf is a constant expression.
In addition, regardless of rf, v, or aaa, they are all used as glvalue core constant expression, hence its value is not significant in this example.
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