std::is_constant_evaluated() 是 c++20 引入的用于区分 constexpr 函数当前是否在常量求值上下文中执行的内联函数,返回 bool 值,需在 constexpr 或 consteval 函数体内使用,典型模式为 if (std::is_constant_evaluated()) { 编译期逻辑 } else { 运行时逻辑 }。

std::is_constant_evaluated() 是 C++20 引入的一个内联函数,用于在运行时或编译期都能安全调用的 constexpr 函数中,**区分当前代码是否正在常量求值(即编译期)上下文中执行**。
为什么需要它?
在 C++17 及以前,constexpr 函数必须“既能编译期执行,也能运行时执行”,但函数内部无法感知自己正以哪种方式被调用。这导致一些场景难以兼顾:比如想在编译期用轻量逻辑(如查表),而在运行时用更通用但非 constexpr 的实现(如调用 std::sqrt)。C++20 之前只能靠重载或宏绕行,不直观也不安全。
std::is_constant_evaluated() 填补了这个空白——它像一个“编译期探测开关”,返回 true 表示当前求值发生在常量表达式中(如 static_assert、consteval 函数、字面类型初始化等),false 表示是普通运行时调用。
基本用法和典型模式
它必须出现在 constexpr 函数(或 consteval 函数)体内,且不能单独作为常量表达式使用(例如不能写 static_assert(is_constant_evaluated()) —— 这本身不合法,因为此时不在求值上下文中)。
立即学习“C++免费学习笔记(深入)”;
- 返回值是 bool,无参数,头文件为
aits> - 常见写法是配合 if constexpr 或普通 if(注意:这里用普通 if 就行,不是 if constexpr!因为 is_constant_evaluated() 的结果在编译期已知,但分支逻辑本身可以是非 constexpr 的)
- 典型结构:if (std::is_constant_evaluated()) { /* 编译期路径 */ } else { /* 运行时路径 */ }
一个实用例子:安全的平方根
假设你想写一个 constexpr sqrt,对小整数在编译期查表,对大数或浮点数在运行时调用 std::sqrt:
constexpr double my_sqrt(double x) { if (std::is_constant_evaluated()) { // 编译期:只允许处理简单情况,比如 x 是 0/1/4/9 等完全平方整数 if (x >= 0 && x == std::floor(x)) { int i = static_cast<int>(x); for (int r = 0; r * r <= i; ++r) { if (r * r == i) return r; } } // 编译期不支持的情况,直接报错或返回占位值(但通常应避免让非法调用通过) throw "not a compile-time square"; } else { // 运行时:放心调用标准库 return std::sqrt(x); } }
这样,constexpr double s = my_sqrt(4); 能成功编译,而 double d = my_sqrt(2.5); 也能正常运行 —— 同一个函数,两种行为,由调用上下文自动决定。
注意事项和常见误区
- 它不是编译期断言,不阻止运行时调用;只是提供信息,后续逻辑仍需你保证正确性
- 不要在非 constexpr 函数里调用它(虽然某些编译器可能不报错,但行为未定义)
- 在 consteval 函数中调用它,结果一定为 true;但它本身不是 consteval 函数
- 它不能用于判断模板实例化时机或 constexpr if 的条件,仅反映当前函数调用的求值阶段
基本上就这些。它不复杂,但容易忽略——尤其当你开始混合编译期优化和运行时灵活性的时候,这个小函数就成了关键支点。