C++20 | std::is_constant_evaluated() 和 const 变量

问题描述 投票:0回答:2

让我们考虑以下代码:

#include <type_traits>

int foo(int arg) {
    if (std::is_constant_evaluated()) {
        return 1;
    } else {
        return 0;
    }
}  

int main() {
    const auto b = foo(0);
    return b;
}

使用 gcc 和 clang 都返回 0。我本来希望它返回 1。

如果

foo()
被制作为
constexpr
,而
b
被简单地保留为
const
,那么它确实返回 1。

我在这里缺少什么?谢谢!

c++ c++20 constexpr
2个回答
8
投票

std::is_constant_evaluated()
当且仅当 [meta.const.eval]:

时返回 true

调用的计算发生在显然是常量计算的表达式或转换的计算中

这个术语“明显不断评估”(定义见here),指的是必须不断评估的上下文。对非

constexpr
函数(这里最近的封闭上下文)的调用是never常量评估,因为它是非
constexpr
,所以这直接不是“明显的常量评估”。

一旦我们成功了

constexpr
,我们就陷入了这个奇怪的遗留怪癖中。在引入
constexpr
的 C++11 之前,我们仍然可以做这样的事情:

template <int I> void f();

const int i = 42; // const, not constexpr
f<i>();           // ok
基本上,我们专门针对声明为 const 的整型(和枚举)类型进行了这种划分,并使用常量表达式进行初始化。这些仍然算作常量表达式。

所以这个:

const auto b = foo(0);

如果
foo(0)
是一个整型常量表达式,那么

b

 可以用作编译时常量(如果它在命名空间范围内,则将被常量初始化
)。所以这里发生的是我们进行两步解析。我们首先尝试评估 
foo(0),就好像它是一个常量表达式一样,然后,如果失败,则退回到 not
 这样做。
在第一个解析中,将 foo(0)

计算为常量,

is_constant_evaluated()

 是(根据定义)
true
,因此我们得到 
1
。解析成功,因此我们最终得到 
b
 作为编译时常量。


对于命名空间范围的变量,常量初始化也是一个重要的概念 - 避免静态初始化顺序惨败。它导致了其他粗糙的例子(参见

P0595)。 这里重要的事情基本上是:is_constant_evaluated()

应该只打开来选择编译时安全算法与运行时算法,而不是实际影响结果的语义。


您必须小心使用地点和方式

5
投票
。 C++ 中有 3 种函数,

is_constant_evaluated

 仅在其中一种中有意义。
// a strictly run-time function
int foo(int arg) 
{
    if (std::is_constant_evaluated()) // pointless: always false
        // ...
}

// a strictly compile time function
consteval int foo(int arg) 
{
    if (std::is_constant_evaluated())  // pointless: always true
        // ...
}

// both run-time and compile-time
constexpr int foo(int arg) 
{
    if (std::is_constant_evaluated())  // ok: depends on context in 
                                       // which `foo` is evaluated
        // ...
}

另一个值得指出的常见错误是
is_constant_evaluated

if constexpr

 条件下也没有任何意义:
{
    if constexpr (std::is_constant_evaluated()) // pointless: always true
                                                // regardless of whether foo 
                                                // is run-time or compile-time
}


© www.soinside.com 2019 - 2024. All rights reserved.