When reading the slides about constexpr the introduction is about \"surprisingly dynamic initialization with consts\". The example is
struct S {
st
In the first example, d
is not initialized by a constant expression, because S::c
is not
a non-volatile const object with a preceding initialization, initialized with a constant expression
(see C++11 [expr.const]p2, bullet on lvalue-to-rvalue conversions), because the initialization of S::c
does not precede the initialization of d
. Therefore static initialization will be used for S::c
(because it is initialized by a constant expression), but dynamic initialization can be used for d
.
Since static initialization precedes dynamic initialization, d
would be initialized to 50
by its dynamic initializer. The compiler is permitted to convert the dynamic initialization of d
to static initialization, but if it does, it must produce the value that d
would have had if every variable which could have used dynamic initialization had, in fact, used dynamic initialization. In this case, d
is initialized to 50
either way. See C++11 [basic.start.init]p2 for more information on this.
There is no way to add constexpr
to the first example to guarantee that static initialization is used for d
; in order to do that, you must reorder the initializations. However, adding constexpr
will produce a diagnostic for the first example, which will at least allow you to ensure that dynamic initialization is not used (you get static initialization or a compilation error).
You can update the second case to ensure that static initialization is used as follows:
struct S {
static const int c; // do not use constexpr here
};
constexpr int S::c = 5;
constexpr int d = 10 * S::c;
It is ill-formed to use constexpr
on a variable declaration which is not a definition, or to use it on a variable declaration which does not contain an initializer, so const
, not constexpr
must be used within the definition of struct S
. There is one exception to this rule, which is when defining a static constexpr
data member of a literal, non-integral type, with the initializer specified within the class:
struct T { int n; };
struct U {
static constexpr T t = { 4 };
};
constexpr T U::t;
In this case, constexpr
must be used in the definition of the class, in order to permit an initializer to be provided, and constexpr
must be used in the definition of the static data member, in order to allow its use within constant expressions.