Self-Initialization of a Static Constexpr Variable, Is It Well-Formed

Should constexpr initialization happen before other initialization

For static storage duration objects initialization must happen in this order:

  1. Zero-initialization.
  2. Constant initialization (i.e. constexpr).
  3. Dynamic initialization.

Relevant standardeese,

C++14 §3.6.2/2:

Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5)
before any other initialization takes place. […] Constant initialization is performed: […] if an object with static or thread storage duration is initialized by a constructor call, and if the
initialization full-expression is a constant initializer for the object; […] Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.

The same paragraph defines (breaking the flow of text, so I removed it above)

A constant initializer for an object o is an expression that is a constant expression, except that it may also invoke constexpr constructors for o and its subobjects even if those objects are of non-literal class types.


In the reported example, which I've verified with Visual C++ 2015, the dynamic initialization of the static storage duration object tst takes place before the constant initialization of the static storage duration object coord, and that's a compiler bug.

Is initialization of static member of a class guaranteed before initialization of a static object of that class?

In the code, would mFunc be initialized to nullptr before myClassObj gets created? The reason for the query is that if the order is not guaranteed, then mFunc may get initialized again to nullptr.

The answer to the question is "Yes".

Setting aside the issue of initialization of thread specific objects, initialization of non-local variables is carried out in the following order.

  1. All variables are zero-initialized (order not specified). This is called zero initialization.
  2. All variables that can be initialized using constant values are initialized. This is called constant initialization.

Those ( 1 and 2 above) are called static initialization.

After that, dynamic initialization is performed.

In your case, MyClass::mFunc is initialized using constant initialization while myClassObj is initialized using dynamic initialization. Hence, the former is guaranteed to be initialized first.

More on this topic can be found at https://timsong-cpp.github.io/cppwp/n3337/basic.start.init.

Initialize C++ const variable with itself

Its name is "undefined behaviour" and setting i to 0 is just one possible outcome.

Does static constexpr variable inside a function make sense?

The short answer is that not only is static useful, it is pretty well always going to be desired.

First, note that static and constexpr are completely independent of each other. static defines the object's lifetime during execution; constexpr specifies that the object should be available during compilation. Compilation and execution are disjoint and discontiguous, both in time and space. So once the program is compiled, constexpr is no longer relevant.

Every variable declared constexpr is implicitly const but const and static are almost orthogonal (except for the interaction with static const integers.)

The C++ object model (§1.9) requires that all objects other than bit-fields occupy at least one byte of memory and have addresses; furthermore all such objects observable in a program at a given moment must have distinct addresses (paragraph 6). This does not quite require the compiler to create a new array on the stack for every invocation of a function with a local non-static const array, because the compiler could take refuge in the as-if principle provided it can prove that no other such object can be observed.

That's not going to be easy to prove, unfortunately, unless the function is trivial (for example, it does not call any other function whose body is not visible within the translation unit) because arrays, more or less by definition, are addresses. So in most cases, the non-static const(expr) array will have to be recreated on the stack at every invocation, which defeats the point of being able to compute it at compile time.

On the other hand, a local static const object is shared by all observers, and furthermore may be initialized even if the function it is defined in is never called. So none of the above applies, and a compiler is free not only to generate only a single instance of it; it is free to generate a single instance of it in read-only storage.

So you should definitely use static constexpr in your example.

However, there is one case where you wouldn't want to use static constexpr. Unless a constexpr declared object is either ODR-used or declared static, the compiler is free to not include it at all. That's pretty useful, because it allows the use of compile-time temporary constexpr arrays without polluting the compiled program with unnecessary bytes. In that case, you would clearly not want to use static, since static is likely to force the object to exist at runtime.

Is this self initialization valid?

I'm pretty sure it's defined, and x should have the value 1. §3.6.2/1 says: "Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place."

After that, I think it's all pretty straightforward.

Initializing a static constexpr from an incomplete type because of a template base class

I think you shall use lazy initialization. Actually Derived is still incomplete type; because the compiler don't know its size yet.

So the code shall be:

struct Derived : public Base<Derived>
{
constexpr Derived(int x) : Base(x) {}

static constexpr Derived getLIFE()
{
return Derived(34);
}
};

EDIT:
Same incomplete type behavior can be reproduced using this snippet:

struct MyStruct
{
static constexpr int x = sizeof(MyStruct);
};

Why initialization of a static variable is restricted to constant expressions?

Static initialization (technically constant initialization) requires constant expressions, but static storage duration variables do not.

int x;                        // 0 initialized
int y = 49; // statically initialized
int z = 2 * sizeof(int) + 1; // statically initialized
int m = 2 * z; // dynamically or statically initialized

3.6.2 Together, zero-initialization and constant initialization are called static initialization; all other initialization is
dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.

Dynamic initialization can rely on functions and other things that can't be decided at compile time. The compiler is allowed to perform static initialization if it can determine the result.

The example you posted will work, although it can lead to trouble with more complicated initialization, as some variables can be initialized dynamically or statically:

inline double fd() { return 1.0; }
extern double d1;
double d2 = d1; // unspecified:
// may be statically initialized to 0.0 or
// dynamically initialized to 1.0
double d1 = fd(); // may be initialized statically to 1.0

static constexpr member of same type as class being defined

If I interpret the Standard correctly, it isn't possible.

(§9.4.2/3) [...] 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. [...]

From the above (along with the fact that there is no separate statement about non-literal types in static data member declarations), I believe it follows that a static data member that is constexpr must be a literal type (as defined in §3.9/10), and it must have its definition included in the declaration. The latter condition could be satisfied by using the following code:

struct Foo {
constexpr Foo() {}
static constexpr Foo f {};
};

which is similar to your Attempt 1, but without the class-external definition.

However, since Foo is incomplete at the time of declaration/definition of the static member, the compiler can't check whether it is a literal type (as defined in §3.9/10), so it rejects the code.

Note that there is this post-C++-11 document (N3308) which discusses various problems of the current definition of constexpr in the Standard, and makes suggestions for amendments. Specifically, the "Proposed Wording" section suggests an amendment of §3.9/10 that implies the inclusion of incomplete types as one kind of literal type. If that amendment was to be accepted into a future version of the Standard, your problem would be solved.



Related Topics



Leave a reply



Submit