Consider this example:
template<int const& rf>
struct A{
void fun(){
constexpr int v = rf; //#1
}
};
int const object = 0;
int main(){
A<object> a;
a.fun();
}
GCC and Clang both agree that rf
can be used as a constant expression.
However, in this case, rf
is an id-expression. Hence, only the id-expression satisfies the following rule can it be used in a constant expression. The relevant rule is:
[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;
For the id-expression rf
at #1
, its lifetime does not begin within the evaluation of initialization. So, bullet 2 is not satisfied here. At the view of the declaration constexpr int v = rf;
where id-expression rf
does not have a preceding initialization. For bullet 1, the relevant rule says:
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.
rf
is not constant-initialized since it neither has an initializer nor its default-initialization results in some initialization being performed. So, the id-expression rf
used in #1
will violate [expr.const#5.12]. Hence, it cannot be used in #1
. Actually, all compilers agree rf
can be used in constant-expression(it also conforms to intuitive). However, the rule in the standard conflicts here. How to interpret this? Does it lack wording for a non-type template parameter that can be used in a constant expression?