Skip to content

consteval, constinit, constexpr, const

  • consteval (only function)
    function executed at compile time, “immediate function”, each invocation creates a compile-time constant, is inline, all contents of the function must be resolved at compile time (e.g. it is not possible to pass runtime variables to the function)
    Example: consteval int Sqr(int n) {return n*n;}
  • constinit (only variable)
    variable initialized at compile time, possible for thread local variables or for global static data which are allocated when the program starts (global variables, static variables, static class members), variable can be changed at runtime (no constness)
    Example: constinit auto globalNumber = Sqr(7);
  • constexpr (function and variable)
    function executed at compile time or runtime, it is possible to pass runtime variables to the function
    Example: constexpr int SqrRunOrCompileTime(int n) {return n*n;}
    Guaranteed to be called at compile time:
    constexpr int myNum = SqrRunOrCompileTime(4);
    Depends on compiler/optimization whether called at run/compiletime:
    int myNum2 = SqrRunOrCompileTime(4); (use a consteval function to ensure compiletime execution)
    constexpr variables are const and cannot be changed at runtime
  • const (variable)
    after initialization the variable cannot be changed

Static initialization order fiasko

Problem:
Static variables within one translation unit are initialized according to their definition order. A static variable within translation unit B may be defined with usage of a static variable within translation unit A. It may depend on the current link order whether variables of unit A or those of unit B are runtime-initialized first. This is a problem when a static variable cannot be initialized at compile time. In this case it is only guaranteed that the variable is zero-initialized

Example for unit A:
static int SomeVal = SomeRuntimeFunc();
// zero-initialized at compile time, later (before or after unit B) initialization by calling SomeRuntimeFunc())

Example for unit B:
static int SomeOtherVal = SomeVal; // may result in 0 or the return value of SomeRuntimeFunc()

Possible solutions:

  • avoid dependencies on static variables within other translation units
  • use a getter function with lazy initialization of a static with local scope
    Unit A:
    int& SomeVal()
    {
    static int staticA = SomeRuntimeFunc();
    return staticA;
    }

    C++11 guarantees proper and threadsafe initialization of static variables with local scope.
    From unit B now call
    static int SomeOtherVal = SomeVal();
  • If possible use constinit for compiletime initialization (C++20)
    Unit A:
    constinit static int SomeVal = SomeCompiletimeFunc()