std :: is_constant_evaluated行为

met*_*fox 17 c++ constexpr c++20 if-constexpr

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
}
Run Code Online (Sandbox Code Playgroud)

根据这些结果,我得出以下结论:

  • if constexpr (std::is_constant_evaluated())总是评估 true分支.因此,使用这种结构是没有意义的.

  • 如果编译器在编译时评估变量, std::is_constant_evaluated())true无论该变量是否明确注释constexpr.

我对吗?

Sto*_*ica 13

if constexpr需要一个条件的常量表达式.因此is_constant_evaluated,在这样的背景下,当然总会如此.

这是一个常规的意思if.目的是constexpr在常量表达式中求值时,不要进入函数中非法的代码路径.但是让它在运行时执行.它不是完全消除函数中的那些代码路径.

  • @ user463035818`constexpr`表示"存在可以允许编译时评估的此函数的参数".它并不意味着"此函数将始终在编译时进行评估".这意味着例如`std :: abs`可以是`constexpr`:当使用`constexpr`参数调用时,它可以在编译时进行计算,但它仍然可以在运行时正常使用. (4认同)

Bar*_*rry 12

这是我对此的看法,也许你会发现这有用......也许不是.请注意,我认为写作if constexpr (std::is_constant_evaluated())将是一个非常常见的错误,并且它很容易陷入陷阱.但希望编译器能够诊断出这种情况.


我们基本上有两个不同的代码规则 - 正常运行时代码的典型规则,以及用于constexpr编程的常量表达式的限制.这些是expr.const限制:没有UB,没有reinterpret_cast等等.这些限制从语言标准到语言标准不断降低,这很好.

基本上,控制流(从代码路径的角度来看)在处于"完全运行时"模式和constexpr模式之间交替.一旦我们进入constexpr模式(无论是通过初始化constexpr对象还是评估模板参数或......),我们都会待在那里直到我们完成...然后我们又回到完全运行时模式.

什么is_constant_evaluated()做无非是:我是在constexpr模式?它告诉您是否在需要常量表达式的上下文中.

在那个视图中,让我们来看看if constexpr (is_constant_evaluated()).无论我们过去处于什么状态,都if constexpr需要一个常量表达式作为其初始化,所以如果我们不在那里,这会将我们提升到constexpr模式.因此,这is_constant_evaluated()是真的 - 无条件.

但是,对于if (is_constant_evaluated()),简单if不会改变运行时和constexpr之间的状态.所以这里的值取决于调用它的上下文.初始化test4将我们置于constexpr模式,因为它是constexpr对象.在初始化期间,我们遵循常量表达式规则......所以is_constant_evaluated()是真的.但是一旦我们完成了,我们就会回到运行时规则......所以在初始化时test5,is_constant_evaluated()是假的.(然后test6是一个不幸的语言特殊情况 - 您可以使用常量积分变量作为常量表达式,因此我们以相同的方式处理它们的初始化以用于这些目的.)

  • @metalfox我怀疑这将是一个非常普遍的误解.我将在答案中添加一个注释 (3认同)
  • GCC 10+ 将警告“if constexpr”情况:https://gcc.gnu.org/ml/gcc-patches/2019-08/msg01841.html (2认同)