显式常量求值表达式:constexpr与consteval为何存在行为差异?
constexpr与consteval的常量求值行为差异解析
示例代码
#include <iostream> #include <string_view> [[nodiscard]] constexpr std::string_view DispCExpr(int) noexcept { if (std::is_constant_evaluated()) { return "consteval\n"; } else { return "not consteval\n"; } } [[nodiscard]] consteval std::string_view DispCEval(int) noexcept { // in consteval function std::is_constant_evaluated() is always true if (std::is_constant_evaluated()) { return "consteval\n"; } else { return "not consteval\n"; } } int main(int argc, char**) { constexpr std::string_view sv1 = DispCExpr(2); std::cout << sv1; // constant evaluated std::string_view sv2 = DispCExpr(2); std::cout << sv2; // not constant evaluated! std::string_view sv3 = DispCEval(2); std::cout << sv3; // constant evaluated! // KO: normal argc not known at compile time // std::string_view sv4 = DispCEval(argc); // std::cout << sv4; // constant evaluated }
行为差异的核心原因
1. sv2的运行时求值逻辑
constexpr函数的常量求值是可选触发的,只有当函数调用属于**显式常量求值表达式(manifestly constant-evaluated)**时,编译器才会强制在编译期计算结果:
- 显式常量求值场景包括:初始化
constexpr/constinit变量、static_assert的参数、constexpr if的条件、模板实参推导等。 - 用编译期常量调用
constexpr函数初始化非constexpr变量时,不属于显式常量求值场景——C++标准允许编译器选择运行时执行该函数,此时std::is_constant_evaluated()返回false,因此输出not consteval。
2. sv3的强制编译期求值逻辑
consteval函数的定义本身就带有强制常量求值的约束:
- 任何
consteval函数的调用都必须在编译期完成常量求值,编译器会直接拒绝无法在编译期计算的调用(比如用argc这类运行时参数调用)。 - 在
consteval函数内部,std::is_constant_evaluated()永远返回true,因为这类函数的执行上下文必然是编译期常量求值环境。
显式常量求值的关键区别
显式常量求值表达式是标准明确规定必须在编译期计算的场景,constexpr函数只有被用于这类场景时才会进入常量求值模式;而consteval函数的所有调用都属于显式常量求值,因此无论使用场景如何,都会触发编译期计算。
内容的提问来源于stack exchange,提问作者Oersted
相关产品推荐
相关产品推荐

