std::is_constant_evaluated() 是仅在 constexpr 函数体内有效的编译期感知内建函数,返回当前是否处于常量求值路径;它不检测类型是否支持 constexpr 赋值,后者取决于类的 constexpr 赋值运算符及成员可常量求值性。

std::is_constant_evaluated 是什么,它不能判断类是否可被常量求值赋值
std::is_constant_evaluated() 是一个运行时不可见、编译期感知的内建函数,它**只在 constexpr 函数体内有意义**,返回 true 当前上下文正处在编译期常量求值路径中(比如模板实例化、constexpr 变量初始化),否则返回 false。它不检查类型本身是否“可被常量求值”,更不判断某个类能否用于 constexpr 赋值——那是由类定义决定的。
常见误解是拿它当“类型检测工具”,比如写:
static_assert(std::is_constant_evaluated(), "must be consteval"); // 错!编译失败
这行代码本身就不合法:std::is_constant_evaluated() 不能出现在常量表达式外的静态断言里,因为它不是常量表达式(它依赖求值时机)。
判断一个类是否支持 constexpr 赋值,看它的赋值运算符和成员
一个类要能参与常量求值中的赋值(如 constexpr T a; a = b;),必须满足:
- 有
constexpr版本的拷贝/移动赋值运算符(显式声明或隐式生成) - 所有非静态数据成员都支持 constexpr 赋值(即其类型本身满足该条件)
- 若含用户定义的赋值运算符,该函数必须是
constexpr且函数体中所有操作都允许在常量求值中执行(无动态内存、无虚调用、无未定义行为等)
例如:
struct Trivial {
int x;
constexpr Trivial& operator=(const Trivial&) = default; // OK:隐式 constexpr
};
而下面这个不行:
struct Bad {
std::string s; // std::string 构造/赋值非 constexpr(C++20 起仍不支持)
constexpr Bad& operator=(const Bad&) = default; // ❌ 实际无法用于 constexpr 上下文
};
注意:std::is_trivially_copyable_v 或 std::is_pod_v 只反映布局属性,**不保证 constexpr 赋值可行**;真正关键的是 std::is_trivially_assignable_v ——但它也只是编译期可赋值性检查,不等于“可在常量求值中赋值”。
如何实测某个类能否在 constexpr 中完成赋值
最可靠的方式是直接写一个最小 constexpr 场景并让编译器验证:
- 定义一个
constexpr变量,用目标类类型 - 在另一个
constexpr函数中对其执行赋值,并返回结果 - 用
static_assert触发编译期求值
示例:
struct S { int v; constexpr S(int i) : v(i) {} };
constexpr S make_s() { S s{0}; s = S{42}; return s; }
static_assert(make_s().v == 42); // 若 S 不支持 constexpr 赋值,此处编译失败
如果想泛化测试,可封装为模板 SFINAE 检测(但 C++20 前较繁琐);C++20 起可用 consteval 强制编译期执行:
template<typename t>
consteval bool can_constexpr_assign() {
T a{}, b{};
a = b; // 这里若失败,整个 consteval 函数不成立
return true;
}</typename>
std::is_constant_evaluated 的典型正确用法
它唯一合理用途是:在同一个函数里为编译期和运行期提供不同实现路径,且该函数本身是 constexpr 的。比如避免在常量求值中调用禁止的操作:
constexpr int safe_sqrt(int x) {
if (x (std::sqrt(x));
}
}
注意点:
- 不能在
consteval函数里调用它(因为 consteval 函数只能在编译期求值,std::is_constant_evaluated()必然返回true,失去意义) - 不能在非
constexpr函数中调用它(编译器会报错) - 它不是类型特征,无法用于
std::enable_if或requires子句中做约束
真正难的不是记住语法,而是意识到:类型能否用于常量求值,取决于其定义细节;而 std::is_constant_evaluated() 只是一个“上下文开关”,它不回答“能不能”,只回答“此刻是不是”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











