GCC9已经实现了std::is_constant_evaluated。我玩了一点,我意识到这有点棘手。这是我的测试:
constexpr int Fn1()
{
if constexpr (std::is_constant_evaluated())
return 0;
else
return 1;
}
constexpr int Fn2()
{
if (std::is_constant_evaluated())
return 0;
else
return 1;
}
int main()
{
constexpr int test1 = Fn1(); // Evaluates to 0
int test2 = Fn1(); // Evaluates to 0
int const test3 = Fn1(); // Evaluates to 0
constexpr int test4 = Fn2(); // Evaluates to 0
int test5 = Fn2(); // Evaluates to 1
int const test6 = Fn2(); // Evaluates to 0
}根据这些结果,我得出了以下结论:
if constexpr (std::is_constant_evaluated())总是计算true分支。因此,使用这种结构是没有意义的。std::is_constant_evaluated())是true,无论该变量是否显式注释constexpr。我说的对吗?
发布于 2019-01-18 10:09:43
if constexpr需要条件的常量表达式。因此,在这种情况下,is_constant_evaluated当然总是正确的。
这是为了一个普通的if。其目的是不进入在constexpr函数中在常量表达式中求值时非法的代码路径。而是让它在运行时执行。它并不是要从函数中完全消除这些代码路径。
发布于 2019-01-18 15:27:13
我是这么想的,也许你会觉得这很有帮助.也许不会。请注意,我认为编写if constexpr (std::is_constant_evaluated())是一个非常常见的错误,这是一个很容易陷入的陷阱。但希望编译器能够诊断出这种情况。提交的91428,这是固定gcc 10.1。
我们本质上有两种不同的代码规则--正常运行时代码的典型规则,以及用于constexpr编程的常量表达式的限制。这些都是expr.const的限制:没有UB,没有reinterpret_cast等,这些限制从语言标准到语言标准不断减少,这是很好的。
基本上,控制流(从代码路径的角度来看)在“完全运行时”模式和constexpr模式之间交替进行。一旦我们进入constexpr模式(无论是通过初始化constexpr对象或计算模板参数或.),我们将一直呆在那里直到完成.然后我们又回到了完全运行模式。
is_constant_evaluated()所做的只是简单地说:我是否处于固定模式?它告诉您,如果您所处的上下文需要常量表达式。
在这个视图中,让我们看看if constexpr (is_constant_evaluated())。无论我们过去处于何种状态,if constexpr都需要一个常量表达式作为初始化,因此如果我们还没有在那里,这就会将我们提升到constexpr模式。因此,is_constant_evaluated()是真的--无条件的。
但是,对于if (is_constant_evaluated()),一个简单的if并不会在运行时和运行时之间改变我们的状态。因此,这里的值取决于从哪个上下文调用的。初始化test4会使我们进入constexpr模式,因为它是一个constexpr对象。在初始化过程中,我们遵循常量表达式规则.所以is_constant_evaluated()是真的。但一旦我们完成了我们又回到了运行规则..。因此,在test5的初始化中,is_constant_evaluated()是假的。(然后,test6是一种不幸的语言特例--您可以使用常量积分变量作为常量表达式,因此我们以相同的方式处理它们的初始化。)
https://stackoverflow.com/questions/54251530
复制相似问题