学习定位:现代 C++ 核心知识。C++20 路线中先掌握“编译期常量、constexpr 函数、if constexpr”即可;consteval、复杂编译期计算和模板元编程可后续按需补。
1. 是什么
constexpr 声明可在编译期求值的变量或函数。它让计算从运行期前置到编译期,消除运行时开销,并允许将结果用于编译期上下文(数组大小、模板实参、static_assert 等)。
2. 比 const 强在哪
const只保证不可修改,值可以在运行期确定。constexpr要求编译期就要知道值,所以能用于const无法胜任的场合。
int n = std::rand();
const int a = n; // ✅ 运行期常量
constexpr int b = n; // ❌ 编译错误:n 不是常量表达式
constexpr int max = 100;
int arr[max]; // ✅ 编译期常量用作数组大小3. 何时用 const vs constexpr
| 场景 | 使用 |
|---|---|
值在运行期才能确定(用户输入、rand() 等) | const |
| 只需保证对象不被修改,不要求编译期可用 | const |
| 值在编译期就能确定(字面量、编译期计算) | constexpr |
需要用于数组大小、模板参数、static_assert 等 | constexpr |
| 函数希望能在编译期执行以提升性能 | constexpr 函数 |
4. C++17 核心特性与示例
4.1 constexpr 变量
constexpr int answer = 42;
constexpr double pi = 3.14159;
constexpr const char* msg = "hello";4.2 constexpr 函数(C++14 起已支持循环/分支,C++17 延续)
constexpr int factorial(int n) {
int result = 1;
for (int i = 2; i <= n; ++i)
result *= i;
return result;
}
constexpr int f5 = factorial(5); // 编译期得 1204.3 if constexpr(C++17 新增)
编译期条件分支,被丢弃的分支不会实例化,允许写出“按类型分派”的模板代码。
template<typename T>
auto to_string(T value) {
if constexpr (std::is_arithmetic_v<T>) {
return std::to_string(value); // 数值类型走这里
} else if constexpr (std::is_same_v<T, std::string>) {
return value; // 字符串直接返回
} else {
static_assert(sizeof(T) == 0, "Unsupported type");
}
}4.4 constexpr 构造函数与类
struct Point {
int x, y;
constexpr Point(int x_, int y_) : x(x_), y(y_) {}
constexpr int norm() const { return x * x + y * y; }
};
constexpr Point p(3, 4);
constexpr int dist = p.norm(); // 255. 误用 constexpr 示例
int get_value() { return 10; } // 非 constexpr 函数
constexpr int v = get_value(); // ❌ 编译错误
int n;
std::cin >> n;
constexpr int s = n * 2; // ❌ 编译错误:n 不是常量6. 总结
- 需要编译期确定性 →
constexpr - 仅需运行期只读 →
const - C++17 的
if constexpr让泛型代码更简洁,消除无效分支实例化。 constexpr不是万能钥匙,强行用在运行期值上会直接编译失败。