Interestingly, if we use Blob::a
instead, clang
does not complain:
auto c = Blob::a;
This should not matter for determining if the it is odr-used or not. So this looks like a clang
bug which I can reproduce on clang 3.7 using no optimization only. We can tell this is an odr issue since adding a out of class definition fixes the issue (see it live):
constexpr float Blob::a ;
So when do you need to define a static constexpr class member? This is covered in section 9.4.2
[class.static.data] which says (emphasis mine going forward):
A static data member of literal type can be declared in the
class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer
in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both
these cases, the member may appear in constant expressions. —end note ] The member shall still be defined
in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not
contain an initializer.
It requires a definition if it is odr-used. Is it odr-used? No, it is not. The original C++11 wording in section 3.2
[basic.def.odr] says:
An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression
thereof. A variable 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.
a
satisfies both conditions, it is a constant expression and the lvalue-to-rvalue conversion is immediately applied. Defect Report 712 has changed the wording which applies to C++11 since it is a defect report and 3.2
now says:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used unless applying the
lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any non-trivial
functions and, if x is an object, ex is an element of the set of potential results of an expression e, where
either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression
The potential result that matches would be:
If e is an id-expression (5.1.1), the set contains only e.
it is a constant expression and the lvalue-to-rvalue conversion is applied so it is not odr-used.