consteval 说明符 (C++20 起)
来自cppreference.com
consteval- 指定函数是立即函数(immediate function),即每次调用该函数必须产生编译时常量。
解释
consteval 说明符声明函数或函数模板为立即函数,即该函数的每次潜在求值的调用都必须(直接或间接)产生编译时常量表达式。
立即函数是 constexpr 函数,并且在情况符合时必须满足相应要求。与 constexpr 一样,consteval 说明符蕴含 inline。不过,它不可应用于析构函数、分配函数或解分配函数。
指定了 consteval 的函数或函数模板声明不能同时指定 constexpr,而且该函数或函数模板的任何重复声明也都必须指定 consteval。
当最内层的非块作用域不是某个立即函数的函数形参作用域或 consteval if 语句的 true 分支(C++23 起)时,对立即函数的潜在求值的调用必须产生常量表达式;这种调用称为立即调用(immediate invocation)。
consteval int sqr(int n)
{
return n*n;
}
constexpr int r = sqr(100); // OK
int x = 100;
int r2 = sqr(x); // 错误:调用未能产生常量
consteval int sqrsqr(int n)
{
return sqr(sqr(n)); // 在此处不是常量表达式,但是 OK
}
constexpr int dblsqr(int n)
{
return 2 * sqr(n); // 错误:外围函数并非 consteval 且 sqr(n) 不是常量
}
指代某个立即函数的标识表达式,仅可出现在立即调用的子表达式内,或某个立即函数语境(即前述的语境,在其中对立即函数的调用不需要是常量表达式)内。可以取得立即函数的指针或引用,但它们不可逃出常量表达式求值:
consteval int f() { return 42; }
consteval auto g() { return &f; }
consteval int h(int (*p)() = g()) { return p(); }
constexpr int r = h(); // OK
constexpr auto e = g(); // 非良构:指向立即函数的指针不是常量表达式的容许结果
注解
| 功能特性测试宏 | 值 | 标准 | 功能特性 |
|---|---|---|---|
__cpp_consteval |
201811L |
(C++20) | 立即函数 |
202211L |
(C++23) (DR20) |
使 consteval 向上传播
|
关键词
示例
运行此代码
#include <iostream>
// 此函数在输入在编译时已知的情况下可以在编译时求值。否则在运行时执行。
constexpr unsigned factorial(unsigned n)
{
return n < 2 ? 1 : n * factorial(n - 1);
}
// 我们用 consteval 强制函数在编译时求值。
consteval unsigned combination(unsigned m, unsigned n)
{
return factorial(n) / factorial(m) / factorial(n - m);
}
static_assert(factorial(6) == 720);
static_assert(combination(4, 8) == 70);
int main(int argc, const char*[])
{
constexpr unsigned x{factorial(4)};
std::cout << x << '\n';
[[maybe_unused]]
unsigned y = factorial(argc); // OK
// unsigned z = combination(argc, 7); // 错误:'argc' 不是常量表达式
}
输出:
24
参阅
constexpr 说明符 (C++11)
|
指定变量或函数的值能在编译时计算 |
constinit 说明符 (C++20)
|
断言变量拥有静态初始化,即零初始化与常量初始化 |
| 常量表达式 | 定义可以在编译期求值的表达式 |