Given the following code:
struct A { static constexpr int a[3] = {1,2,3}; };
int main () {
int a = A::a[0];
int b [A::a[1]];
}
is
No, it is not odr-used.
First, both your array and its elements are of literal type:
[C++11: 3.9/10]:A type is a literal type if it is:
- a scalar type; or
- a class type (Clause 9) with
- a trivial copy constructor,
- no non-trivial move constructor,
- a trivial destructor,
- a trivial default constructor or at least one constexpr constructor other than the copy or move constructor, and
- all non-static data members and base classes of literal types; or
- an array of literal type.
Now we look up the odr-used rules:
[C++11: 3.2/2]:[..] A variable or non-overloaded function whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied. [..]
And here we've been referred to the rules on constant expressions, which contain nothing prohibiting your initialiser from being a constant expression; the pertinent passages are:
[C++11: 5.19/2]:A conditional-expression is a constant expression unless it involves one of the following as a potentially evaluated subexpression [..]:
- [..]
- an lvalue-to-rvalue conversion (4.1) unless it is applied to
- a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or
- a glvalue of literal type that refers to a non-volatile object defined with
constexpr, or that refers to a sub-object of such an object, or- a glvalue of literal type that refers to a non-volatile temporary object initialized with a constant expression;
- [..]
(Don't be put off by the name of the production, "conditional-expression": it is the only production of constant-expression and is thus the one we're looking for.)
Then, thinking about the equivalence of A::a[0] to *(A::a + 0), after the array-to-pointer conversion you have an rvalue:
[C++11: 4.2/1]:An lvalue or rvalue of type "array ofNT" or "array of unknown bound ofT" can be converted to a prvalue of type "pointer toT". The result is a pointer to the first element of the array.
Your pointer arithmetic is then performed on this rvalue and the result is also an rvalue, used to initialise a. No lvalue-to-rvalue conversion here whatsoever, so still nothing violating "the requirements for appearing in a constant expression".