C++ constexpr 和 std::is_contant_evaluated 之间的交互

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

在 CppNow 演讲中(Don’t constexpr All the Things - David Sankel),它使用以下函数作为示例:

constexpr int f()
{
    if constexpr (std::is_constant_evaluated()) {
       // slow version at runtime but that can be evaluated at compile-time
    } else {
       // fast version at runtime
    }
}

David 说,在这个例子中,函数的定义取决于

std::is_constant_evaluated()
,因此函数在运行时将始终“慢”或在运行时始终“快”。

但同时,

std::is_constant_evaluated()
true
还是
false
取决于使用的上下文,对吧?例如:

const int i = f();

在此示例中,编译将尝试在编译时计算常量

i
的值。为此,编译器调用
f
并将
is_constant_evaluated
设置为
true
来查看会发生什么。如果它可以在编译时评估结果,它就会执行此操作并在编译时设置
i
的最终值。

但是,从其他上下文中,可以将

f()
设置为
std::is_constant_evaluated
来调用
false

因此,如果

std::is_constant_evaluated
根据“调用者上下文”设置为
true
false
,因此两种可能性都发生在代码中的不同点,那么“被调用者”怎么可能只有一个定义呢?

抱歉,如果我的问题没有明确定义,但有些东西我还不太明白,我现在很困惑。

c++ templates template-meta-programming
1个回答
0
投票

David 说,在这个例子中,函数的定义依赖于 std::is_constant_evaluated()

他是说,当

if constexpr
被实例化时,它将仅“打开”两个分支之一,这意味着实例化函数实际上只会使用两个分支之一。

在幻灯片上有一个小错误,考虑到他如何谈论该函数,他可能意味着它是一个函数模板,即开头缺少一个

template<typename T>
或类似的内容。他甚至提到它“通常用于模板”。

但是无论是否是模板,结果都是一样的。

if constexpr
的条件必须是本身常量表达式。因此,无论何时评估它,它都是在编译时而不是运行时评估的。因此,在
std::is_constant_evaluated()
条件下,
true
将始终返回
if constexpr

因此,无论调用者上下文如何,都永远无法采用快速分支,并且如果这是一个模板,它甚至不会被实例化。

这就是为什么

std::is_constant_evaluated
条件中的
if constexpr
总是 错误。

使用 C++23,您可以忘记

std::is_constant_evaluated
的存在。相反,你可以写总是写

if consteval
{
    // compile-time branch
}
else
{
    // runtime branch
}

if consteval
做了
std::is_constant_evaluated()
应该做得更好的事情,并且不允许出现此类错误。

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