← SEARCHABLE ARCHIVE
C / C++ · 2026-08-11

从 C++ 基础到掌握 — 第 17 集

使用 constexpr 和 consteval 进行编译期计算

INTERACTIVE READING MODE →

本博客文章以教学为目的编写。 内容可能存在错误,请结合目标编译器和标准库文档进行确认。

C++ 能在程序启动前完成部分计算。constexpr、consteval 和 constinit 分别表达可常量求值、必须在编译期调用,以及静态初始化。

constexpr 可在两种环境执行

constexpr int Square(int value)
{
    return value * value;
}

constexpr int tableSize = Square(8); // 编译期
int input = ReadInput();
int result = Square(input);          // 运行期

constexpr 函数可以参与常量求值,但不是每次调用都必须发生在编译期。参数为常量且结果用于需要 constant expression 的位置时,编译器必须先求出结果。

consteval 强制编译期调用

consteval unsigned int HashLiteral(std::string_view text)
{
    unsigned int hash = 2166136261u;
    for (char ch : text)
        hash = (hash ^ static_cast<unsigned char>(ch)) * 16777619u;
    return hash;
}

constexpr auto playerId = HashLiteral("Player");

consteval 的每次调用都必须是 constant expression,适合构建时就固定的资源键或协议标签。

哈希仍可能冲突。编译期计算不保证唯一性,因此仍需要冲突策略和原始键验证。

用 if constexpr 移除无效分支

template <typename T>
void Serialize(const T& value, Writer& writer)
{
    if constexpr (std::integral<T>)
        writer.WriteInteger(value);
    else
        value.Serialize(writer);
}

与普通 if 不同,未选择的 if constexpr 分支会从该模板实例中丢弃。另一分支中不适用于当前类型的操作不必成立。

constinit 检查静态初始化

constinit int globalLimit = 64;

constinit 验证 static storage duration 对象能否静态初始化,但不会让对象不可修改;不可修改是 const 的职责。

编译期计算能减少运行期初始化并提前暴露错误,但会增加构建时间、诊断复杂度,有时也会增大二进制。只在规则真正固定且提前验证值得成本时使用。