constexpr 是 C++ 中要求实体必须在编译期求值的关键字,用于声明编译期常量和可在编译期执行的函数,支撑元编程、模板推导、数组大小定义等核心特性。

constexpr 是 C++ 中用于声明“可在编译期求值”的变量、函数或对象的关键字。它不是简单地“建议”编译器优化,而是对语义的约束:被标记为 constexpr 的实体,**必须能在编译期计算出确定结果**(前提是其参数/初始化表达式也满足编译期可求值条件)。这直接支撑了元编程、模板推导、数组大小定义、if constexpr 分支等关键特性,是现代 C++ 性能优化和类型安全的重要基石。
constexpr 变量:编译期常量的明确声明
声明一个 constexpr 变量,意味着它的值在编译时就已确定,且不可修改。编译器会强制检查初始化表达式是否满足“核心常量表达式”(core constant expression)要求。
- 只能用字面量、其他 constexpr 变量、允许在编译期调用的 constexpr 函数来初始化
- 例如:constexpr int N = 10 + 5; ✅(纯字面量运算)
constexpr int M = std::sqrt(16); ❌(std::sqrt 在 C++20 前非 constexpr) - 用途:定义数组长度、模板非类型参数、枚举值、静态断言条件等
constexpr 函数:编译期可执行的“纯函数”
constexpr 函数不等于“一定会在编译期运行”,而表示“**如果传入的参数都是字面量或编译期可知的值,那么该函数调用就可在编译期完成**”。C++14 起放宽限制,支持局部变量、循环、条件分支等;C++20 进一步支持 try/catch、动态内存(有限)、虚函数调用等。
- 函数体需满足“核心常量表达式”规则(早期较严,新版更宽松)
- 示例(C++14+):constexpr int factorial(int n) { return n
调用 constexpr int f5 = factorial(5); → 编译期算出 120 - 若参数含运行时值(如用户输入),则退化为普通函数调用,不报错但失去编译期优势
constexpr 构造函数与字面量类(Literal Types)
类若想拥有 constexpr 对象,需满足:所有成员变量为字面量类型,且至少有一个 constexpr 构造函数。这类类称为“字面量类”,其对象可在编译期创建和使用。
立即学习“C++免费学习笔记(深入)”;
- 构造函数、成员函数、析构函数(C++20)均可标记为 constexpr
- 典型应用:自定义编译期字符串、小型数学向量、状态机配置结构体等
- 例如:struct Point { constexpr Point(int x, int y) : x(x), y(y) {} int x, y; }; constexpr Point p{3, 4};
性能优化的关键逻辑与注意事项
使用 constexpr 的真正价值,在于把本该在运行时做的计算提前到编译阶段,从而消除重复开销、减少二进制体积、提升缓存友好性,并支持更强的编译期检查。
- 不是所有计算都适合 constexpr:递归过深、依赖 I/O 或全局状态、涉及未定义行为的表达式会被拒绝
- 编译时间可能增加:复杂 constexpr 计算(如编译期 JSON 解析、正则匹配)会延长构建过程
- 务必配合 consteval(C++20):当需要“强制仅在编译期求值”时使用,比 constexpr 更严格
- 调试提示:GCC/Clang 报错 “call to non-constexpr function” 表明某处违反了编译期约束,需逐层检查参数和函数定义











