std::is_constant_evaluated() 仅在 constexpr 函数中被编译器明确作为常量表达式求值时返回 true,否则编译失败;必须配合 if constexpr 分支,且两分支需各自满足其上下文约束。

std::is_constant_evaluated() 不是运行时性能开关,它只在被明确要求常量求值的调用点返回 true;写错分支内容或用错上下文,函数直接编译失败。
必须在 constexpr 函数里调用,否则连编译都过不去
这个函数根本不能出现在普通函数中。GCC 和 Clang 会直接报 call to non-constexpr function 'std::is_constant_evaluated'。哪怕你只写一行 return std::is_constant_evaluated();,也得给整个函数加上 constexpr 修饰。
常见错误:
- 在非 constexpr 函数里试图“探测当前是不是编译期”——语法不合法
- 在 lambda 里调用,但 lambda 捕获了非常量变量或调用了非 constexpr 函数——该 lambda 就无法参与常量求值
- 在 C++17 或更早标准下使用——符号未定义,链接失败
调用点决定真假,不是函数声明或参数类型决定的
std::is_constant_evaluated() 返回什么,只看“这次调用是否被编译器当作常量表达式求值”,和函数有没有 constexpr、参数是不是 const int 都无关。
有效触发 true 的场景只有这些:
static_assert(my_func(42) == 17);constexpr int x = my_func(42);-
int arr[my_func(42)];(数组大小) -
template+struct X {}; X(NTTP 推导)y; - 在
consteval函数体内调用(必然为true)
无效场景(一律返回 false):
-
int x = my_func(42);(普通运行时调用) -
const int a = 42; my_func(a);(a是 const,但不是字面量或 constexpr 变量) -
my_func(argv[1]);(运行时输入)
if constexpr 才是唯一安全的分支写法
用普通 if 会导致编译器检查两个分支的合法性。只要 else 分支里有 std::sqrt、new、std::cout 这类运行时专属操作,整个函数就无法用于 static_assert 或模板参数——哪怕你永远不走那个分支。
正确写法必须是:
static_assert
关键点:
-
if constexpr让编译器只实例化进入的分支,另一分支不参与语义检查 - 编译期分支里禁止任何非常量操作:不能调用
std::strlen,不能取非常量全局变量地址,不能用dynamic_cast - 运行时分支虽自由,但它的存在本身会影响函数能否参与常量求值——所以别在里面写调试输出或日志
跨编译器行为差异大,验证只靠 static_assert
Clang 更保守,通常只在 static_assert、NTTP、consteval 等明确场景才返回 true;GCC 12+ 在 constinit 初始化中可能更激进地尝试常量求值,导致行为不一致。
唯一可靠验证方式:
- 写
static_assert(my_func(42) == expected);,能过说明这次调用确实在编译期完成 - 如果失败,
std::is_constant_evaluated()就是false,别猜原因,先检查调用点 - 头文件中定义带
std::is_constant_evaluated()的函数要格外小心——ODR 和模板实例化时机可能让行为不可预测
最易被忽略的一点:它不剪枝、不优化、不加速,只是个信号。你得自己把两套逻辑都写对,且各自满足其上下文约束——编译期分支写错一句,整个 constexpr 路径就崩,而运行时调用却可能完全正常。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











