2

在 C++20 中,我们现在拥有constinit. constexprconsteval

我现在可以保证静态变量是由 aconstexprconsteval函数的结果初始化的constinit。好的

我还可以保证使用consteval在编译时执行的函数的结果来初始化堆栈变量。

但是如何强制运行一个constexpr函数来计算编译时的结果以在堆栈上初始化一个变量?

// 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;
}

如果我们使用constexpr该变量是隐式的 const 并且constinit在这里是不允许的。是否有机会使用函数的编译时间评估结果初始化此 var 而constexpr不会使其成为 const?我只是想知道为什么constinit仅限于静态变量。对我来说没有多大意义。

4

2 回答 2

4

我只是想知道为什么 constinit 仅限于静态变量。对于我的[原文如此],这没有多大意义。

常量初始化和动态初始化是仅适用于具有静态存储持续时间的对象的概念。说明constinit符仅意味着强制我们期望变量将经历前者,而不是后者。它不是一个优化工具,而是一种编码我们的代码应该如何表现的方式。没有它,动态初始化可能会悄无声息地发生,正如任何熟悉该块的 C++ 程序员都可以告诉你的那样,这也意味着静态初始化顺序的惨败可能会发生。

有了constinit,我们要么得到预期的行为,要么得到诊断。它不适用于自动变量,因为它们不会遇到与静态变量相同的问题。

但是,如果您想确保由可以i不断评估的东西进行初始化,那么实现起来并不难。

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

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

如果func(8)不能不断评估,这是一个硬错误。编译器会优化它以加载恒定值吗?很可能。编译器擅长这种事情。

于 2022-01-10T10:19:59.020 回答
3

我认为最好使用consteval函数,但如果你不能改变它,你可以简单地使用一个临时变量,它肯定会在以后优化:

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

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

虽然你可能不喜欢这种方法,但我认为它没有任何问题......

你也可以使用这样的东西(基于 StoryTeller 的想法):

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

它也支持从方法返回引用。

于 2022-01-10T10:01:30.870 回答