Pil*_*esa 38 c++ constexpr c++20
考虑以下程序:
#include <iostream>
#include <type_traits>
constexpr int f() {
if (std::is_constant_evaluated())
return -1;
else return 1;
}
int main() {
int const i = f();
std::cout << i;
}
Run Code Online (Sandbox Code Playgroud)
它打印-1在运行时(wandbox)。
但是,如果我throw在编译时求值时使用该函数:
#include <iostream>
#include <type_traits>
constexpr int f() {
if (std::is_constant_evaluated())
throw -1; // <----------------------- Changed line
else return 1;
}
int main() {
int const i = f();
std::cout << i;
}
Run Code Online (Sandbox Code Playgroud)
它可以编译并输出1(wandbox)。为什么我没有出现编译失败?
Bar*_*rry 38
持续评估很有趣吗?
在该语言中,有一些地方我们尝试进行持续评估,如果失败,我们将退后一步进行非持续评估。静态初始化就是这样一个地方,初始化常量整数是另一个地方。
会发生什么:
int const i = f();
Run Code Online (Sandbox Code Playgroud)
是,这可能是恒定的评估,但它不一定是。因为(非constexpr)常量整数仍可以用作常量表达式,所以如果它们满足所有其他条件,我们必须尝试。例如:
const int n = 42; // const, not constexpr
std::array<int, n> arr; // n is a constant expression, this is ok
Run Code Online (Sandbox Code Playgroud)
因此,我们尝试做-我们将其f()称为常量表达式。在这种情况下,std::is_constant_evaluated()is是true,所以我们用击打分支,throw最终失败。throw在持续评估期间无法执行,因此我们的持续评估失败。
但是,我们回退了,然后再试一次-这次f()以非常量表达式(即std::is_constant_evaluated()is false)的形式调用。该路径成功,给了我们1,所以i用value初始化1。但值得注意的是,i目前还不是一个常量表达式。static_assert(i == 1)因为i的初始值设定项不是常量表达式,所以后续项将格式错误!即使非常数初始化路径恰好(否则)完全满足常数表达式的要求。
请注意,如果我们尝试:
constexpr int i = f();
Run Code Online (Sandbox Code Playgroud)
这将失败,因为我们无法回退到非恒定初始化。