Should constexpr initialization happen before other initialization
For static storage duration objects initialization must happen in this order:
- Zero-initialization.
- Constant initialization (i.e.
constexpr
). - 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 invokeconstexpr
constructors foro
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 tonullptr
beforemyClassObj
gets created? The reason for the query is that if the order is not guaranteed, thenmFunc
may get initialized again tonullptr
.
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.
- All variables are zero-initialized (order not specified). This is called zero initialization.
- 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
How to Get the Position and Draw Rectangle Using Opencv
How to Print the Full Value of a Long String in Gdb
A Fast Method to Round a Double to a 32-Bit Int Explained
How to Use Windbg to Analyze the Crash Dump for Vc++ Application
How to Set the Padding of Qtableview Cells Through CSS
Advantages of Std::For_Each Over for Loop
C++ Equivalent of Stringbuffer/Stringbuilder
C++ Get All Bytes of a File in to a Char Array
Creating a Counter That Stays Synchronized Across Mpi Processes
Non-Defaulted Operator <=> Doesn't Generate == and != in C++20