提问人:ABu 提问时间:10/21/2023 更新时间:10/21/2023 访问量:56
C++ constexpr 和 std::is_contant_evaluated 之间的交互
C++ Interaction between constexpr and std::is_contant_evaluated
问:
在 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();
在此示例中,编译将尝试在编译时计算常量的值。为此,编译器调用 set 来查看会发生什么。如果它可以在编译时计算结果,则它会这样做并在编译时设置 的最终值。i
f
is_constant_evaluated
true
i
但是,从其他上下文中,可以使用设置为 来调用。f()
std::is_constant_evaluated
false
因此,如果设置为或依赖于“调用方上下文”,因此这两种可能性都发生在代码中的不同点,那么“被调用方”怎么可能只有一个定义呢?std::is_constant_evaluated
true
false
对不起,如果我的问题没有明确定义,但有些东西我还没有完全理解,我现在很困惑。
答:
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
if
if
使用 C++23,您可以忘记它的存在。相反,你可以写 总是写std::is_constant_evaluated
if consteval
{
// compile-time branch
}
else
{
// runtime branch
}
if consteval
严格来说,应该做得更好,也不允许出现这种错误。std::is_constant_evaluated()
评论
if constexpr (std::is_constant_evaluated())
应该是 ?if (std::is_constant_evaluated())
std::is_constant_evaluated()
”嗯,这是什么意思?问题是总是在里面返回,你需要普通的。(显然它还有更多问题,因此在 C++23 中)。std::is_constant_evaluated()
true
if constexpr
if
if consteval
constexpr