3

In a code like this:

#include <iostream>

template<int I>
struct A {
    static constexpr int I1 = I + 1;
    static constexpr int I2 = I1 + 1;
};

int main() {
    std::cout << A<1>::I1 << " " << A<1>::I2 << std::endl;
}

is it safe to assume that I2 will get initialized correctly, i.e. that I1 gets initialized before I2?

tmlen
  • 8,533
  • 5
  • 31
  • 84
  • 2
    Does [Static variables initialisation order](https://stackoverflow.com/questions/211237/static-variables-initialisation-order) answer your question? – Drew Dormann Jun 28 '23 at 14:10
  • According to https://en.cppreference.com/w/cpp/language/initialization#Non-local_variables this would only apply to dynamic initialization, not for static initialization of these constexpr members. – tmlen Jun 28 '23 at 14:18
  • also it is not possible to compile it if the line with I2 is put above I1 in this case – tmlen Jun 28 '23 at 14:21
  • 1
    This is [constant static initialization](https://en.cppreference.com/w/cpp/language/constant_initialization), so yes, it's safe. – Mestkon Jun 28 '23 at 14:24

1 Answers1

7

Initialization order isn't really meaningful for anything that's constexpr. A constexpr variable must be initialized by a constant expression, and since constant expressions don't have any side effects, and mutable global state isn't something that exists at compile time, you don't have to worry about initialization order.

If you want to get into the specifics:

Constant initialization is performed if a variable or temporary object with static or thread storage duration is constant-initialized ([expr.const]). [...] Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. All static initialization strongly happens before ([intro.races]) any dynamic initialization.

- https://eel.is/c++draft/basic.start.static#2

Initialization order for static initialization doesn't matter, because everything is being initialized to a compile-time constant. It's only an issue for dynamic initialization.

For constant initialization, the only thing that matters is the order of definition:

static constexpr int I1 = I + 1;  // I1 defined before I2
static constexpr int I2 = I1 + 1; // I2 can use this definition

Any constexpr variable, including static constexpr data members must be initialized where they are defined. Any constant expressions that appear further down in code then inevitably have that definition available, because the program is compiled from top to bottom. In this example, it means that:

  • I1 must always be defined right where it's declared because it's constexpr
  • I2 always has this definition available, because it appears further down in the code
Jan Schultke
  • 17,446
  • 6
  • 47
  • 96