how to guarantee initilization of a stack variable with a compile time constant

243 views Asked by At

In C++20 we now have constinit. constexpr and consteval.

I can now guarantee that a static variable is initialized by the result of a constexpr or consteval function by using constinit. OK

I also can guarantee that a stack variable is initialized with the result of a consteval function executed in compile time.

But how can I force to run a constexpr function to calculate a result in compile time to init a variable on stack?

// Lets assume that we have a much more complex function so that the compiler will not
// always decide to compile time evaluation automatically 
constexpr int func( int i )
{
    return i+2;
}

int main()
{
     ??? int i = func(8);
     ...
     i = 9;
}

If we use constexpr the variable is implicitly const and constinit is not allowed here. Any chance to initialize this var with the compile time evaluated result of a constexpr function without making it const? I am simply wondering why constinit is limited to static variables. For my it makes not much sense.

2

There are 2 answers

4
Afshin On BEST ANSWER

I think it is better to use consteval function, but if you cannot change it, you can simply use a temporary variable which will surely optimize later:

constexpr int func( int i )
{
    return i+2;
}

int main()
{
     constexpr int i1 = func(8);
     auto i2 = i1;
     i2 = 9;
}

Although you may not like this method, I think it works without any problem....

You can also use something like this(Based on StoryTeller idea):

template<typename T> constexpr std::remove_const_t<T> const_eval(T&& res) { return res; }

which support returning references from method too.

5
StoryTeller - Unslander Monica On

I am simply wondering why constinit is limited to static variables. For my[sic] it makes not much sense.

Constant initialization and dynamic initialization are concepts that apply only to objects with static storage duration. The constinit specifier merely means to enforce our expectation that a variable will undergo the former, rather than the latter. It's not an optimization tool, but a way to codify how our code is meant to behave. Without it, dynamic initialization can happen silently, and as any C++ programmer who has been around the block can tell you, that also means the static initialization order fiasco can occur.

With constinit, we either get the expected behavior or a diagnostic. It doesn't apply to automatic variables because they don't suffer from the same problem static variables do.

But if you want to ensure i is initialized by something that can be constant evaluated, then it's not too hard to accomplish.

template<auto result> consteval auto const_eval() { return result; }

int main()
{
     int i = const_eval<func(8)>();
     i = 9;
}

If func(8) cannot be constant evaluated, it's a hard error. Will a compiler optimize it to a load of a constant value? Very likely. Compilers are good at that sort of thing.