第7.6章: consteval
概述
consteval 函数必须在编译期求值。
它不能在运行时运行。如果编译器无法在编译期间求值该函数,
程序就无法编译。
这比 constexpr 更严格。实践中,
consteval 很少需要,但当你想保证某个函数永远不会
在运行时执行时,它很有用。
1. 基础示例
consteval 函数必须在常量表达式中调用。
#include
consteval int double_value(int x)
{
return x * 2;
}
int main()
{
using namespace ::fast_io::iomnp;
constexpr int a = double_value(10); // OK: compile-time
print("a = ", a, "\n");
// int b = double_value(10); // ERROR: cannot call at runtime
}
第二次调用会失败,因为 double_value 不能在运行时运行。
2. 为什么这很少有用
大多数函数并不需要被限制为只能在编译期求值。
需要时 constexpr 已经允许编译期求值,
同时又仍然允许运行时执行。
consteval 只在以下情况有用:
- 你想完全禁止运行时执行
- 你想保证得到编译期常量
- 你想对非法用法立即给出编译期错误
这些情况在普通应用代码中并不常见。
3. 编译期校验
consteval 函数可以强制那些必须在编译期间检查的约束。
#include
consteval int positive(int x)
{
if(x <= 0)
throw "value must be positive";
return x;
}
int main()
{
using namespace ::fast_io::iomnp;
constexpr int a = positive(5); // OK
print("a = ", a, "\n");
// constexpr int b = positive(-3); // compile-time error
}
任何非法输入都会导致编译期失败。
4. 与 constexpr 的区别
constexpr 函数:
- 可以在编译期运行
- 也可以在运行时运行
- 可在两种上下文中使用
consteval 函数:
- 必须在编译期运行
- 不能在运行时运行
- 用法错误会导致编译失败
constexpr int f(int x) { return x + 1; } // flexible
consteval int g(int x) { return x + 1; } // strict
g() 只能在常量表达式中使用。
5. 与 if consteval 的配合
if consteval 检测某个 constexpr 函数是否
正在编译期求值。而 consteval 函数总是在编译期求值。
#include
constexpr int compute(int x)
{
using namespace ::fast_io::iomnp;
if consteval
print("compile-time path\n");
else
print("runtime path\n");
return x * 3;
}
consteval int force_ct(int x)
{
return compute(x); // always compile-time
}
force_ct() 保证 compute() 走编译期
分支。
要点
consteval函数必须在编译期运行。- 它们不能在运行时运行。
- 它们适用于严格的编译期校验与生成。
constexpr灵活;consteval严格。if consteval检测编译期求值,而consteval强制它。- 大多数真实世界的代码并不需要
consteval。