constexpr = 编译期可求值。标记变量 / 函数 / 构造函数,告诉编译器:这个东西能在编译阶段就算出结果,而不是等到程序运行时才算。
区分:const 只是"只读",不一定编译期求值;constexpr 强调"可以编译期计算"。
一、const vs constexpr:最容易混的一对
| 关键字 |
含义 |
求值时机 |
const |
只读,不能改 |
可以运行时求值 |
constexpr |
编译期可计算 |
优先编译期求值,也支持运行调用 |
简单记忆:
const:不能写(只读);
constexpr:能在编译期算。
1 2
| constexpr double pi = 3.1415926; const double pi2 = 3.1415926;
|
二、constexpr 变量
1 2
| constexpr int val = 2 * 2 * 2 * 2; int arr[val];
|
初始化表达式必须编译期可算——传入运行期变量直接编译报错:
1 2 3 4 5
| int n = 10; const int c = n;
constexpr int e = n;
|
三、constexpr 函数
两阶段行为:
| 传入的实参 |
行为 |
| 编译期常量 |
编译期执行,结果是编译期常量 |
| 运行期变量 |
退化成普通函数,运行期执行 |
3.1 C++11 版本(最严格)
C++11 限制极强:函数体只能有一条 return。
1 2 3 4 5 6 7 8 9 10
| constexpr int pow4(int x) { return x * x * x * x; }
int main() { constexpr int res = pow4(2); int a = 3; int b = pow4(a); return 0; }
|
3.2 C++14 版本(放开限制)
C++14 允许 if / for 循环 / 局部变量,写法灵活很多:
1 2 3 4 5 6 7 8 9
| constexpr int sum(int n) { int s = 0; for (int i = 1; i <= n; i++) { s += i; } return s; }
constexpr int total = sum(100);
|
C++20 进一步允许在 constexpr 函数里用 STL(vector / string 等)。
四、constexpr 构造函数
让对象的构造发生在编译期:
1 2 3 4 5 6
| struct Point { int x, y; constexpr Point(int xx, int yy) : x(xx), y(yy) {} };
constexpr Point p(1, 2);
|
五、C++20 新增:consteval / constinit
| 关键字 |
含义 |
consteval |
强制编译期函数,传运行期实参直接编译报错 |
constinit |
保证静态 / 线程局部变量在编译期初始化,规避"静态初始化顺序灾难" |
1 2 3 4 5 6 7 8
| consteval int square(int x) { return x * x; }
int main() { constexpr int a = square(5); int n = 5; return 0; }
|
六、易错点清单
constexpr 不是强制编译期执行,是"允许"。实参是运行期变量时,自动降级为普通运行期函数。
- 复杂超大循环的
constexpr 函数会拖慢编译——甚至编译超时。别在 constexpr 里写几万次循环。
constexpr 函数不能调用非 constexpr 函数(C++11/14,C++20 放宽)。
- 数组大小、模板参数必须编译期常量——必须用
constexpr。
- 构造函数想加
constexpr 必须满足所有成员都能在编译期构造——比如不能有 std::string(C++20 之前)。
七、典型用途
| 用途 |
例子 |
| 编译期常量(数组长度、模板参数) |
constexpr int N = 10; int a[N]; |
| 编译期求值数学函数 |
阶乘、幂、CRC、查表 |
| 编译期校验 |
static_assert(cond); |
| 编译期构造对象 |
几何点、复数、小结构体 |
| 竞赛加速 |
预生成查找表 / 编译期计算三角函数表 |
八、constexpr 决策流程图
flowchart LR
A[调用 constexpr 函数] --> B{实参是否编译期常量}
B -->|是| C[编译期执行<br/>结果是编译期常量]
B -->|否| D[退化成普通函数<br/>运行期执行]
九、极简速记
| 写法 |
含义 |
constexpr int x = 10; |
编译期常量 |
constexpr int f(int x) { return x * x; } |
既可编译期调用,也可运行期调用 |
constexpr Point p(1, 2); |
编译期构造对象 |
consteval int f(int x); |
C++20,强制编译期 |
constinit int x = foo(); |
C++20,保证静态变量编译期初始化 |
十、小结
constexpr = "能在编译期算",比 const 强;
- 既可编译期调用,也可运行期调用——传入的实参决定走哪条路;
- C++11 限制严格(单 return),C++14 放开(支持循环 / 局部变量),C++20 进一步支持 STL;
- 常见用途:数组长度、模板参数、查表、几何对象;
- 写法口诀:"const 只读,constexpr 能算;运行传参自动降级"。