First use of A::a
:
int a = A::a[0];
The initializer is a constant expression, but that doesn't stop A::a
from being odr-used here. And, indeed, A::a
is odr-used by this expression.
Starting from the expression A::a[0]
, let's walk through [basic.def.odr](3.2)/3 (for future readers, I'm using the wording from N3936):
A variable x
[in our case, A::a
] whose name appears as a potentially-evaluated expression ex [in our case, the id-expression A::a
] is odr-used unless
applying the lvalue-to-rvalue conversion to x
yields a constant expression [it does]
that does not invoke any non-trivial functions [it does not] and,
if x
is an object [it is],
ex
is an element of the set of potential results of an expression e
, where either the lvalue-to-rvalue conversion is applied to e
, or e
is a discarded-value expression.
So: what possible values of e
are there? The set of potential results of an expression is a set of subexpressions of the expression (you can check this by reading through [basic.def.odr](3.2)/2), so we only need to consider expressions of which ex
is a subexpression. Those are:
A::a
A::a[0]
Of these, the lvalue-to-rvalue conversion is not applied immediately to A::a
, so we only consider A::a[0]
. Per [basic.def.odr](3.2)/2, the set of potential results of A::a[0]
is empty, so A::a
is odr-used by this expression.
Now, you could argue that we first rewrite A::a[0]
to *(A::a + 0)
. But that changes nothing: the possible values of e
are then
A::a
A::a + 0
(A::a + 0)
*(A::a + 0)
Of these, only the fourth has an lvalue-to-rvalue conversion applied to it, and again, [basic.def.odr](3.2)/2 says that the set of potential results of *(A::a + 0)
is empty. In particular, note that array-to-pointer decay is not an lvalue-to-rvalue conversion ([conv.lval](4.1)), even though it converts an array lvalue to a pointer rvalue -- it's an array-to-pointer conversion ([conv.array](4.2)).
Second use of A::a
:
int b [A::a[1]];
This is no different from the first case, according to the standard. Again, A::a[1]
is a constant expression, thus this is a valid array bound, but a compiler is still permitted to emit code at runtime to compute this value, and the array bound still odr-uses A::a
.
Note in particular that constant expressions are (by default) potentially-evaluated expressions. Per [basic.def.odr](3.2)/2:
An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof.
[expr](5)/8 just redirects us to other subclauses:
In some contexts, unevaluated operands appear (5.2.8, 5.3.3, 5.3.7, 7.1.6.2). An unevaluated operand is not evaluated.
These subclauses say that (respectively) the operand of some typeid
expressions, the operand of sizeof
, the operand of noexcept
, and the operand of decltype
are unevaluated operands. There are no other kinds of unevaluated operand.