C++26 constexpr 异常详解:编译期也能 throw/catch
本文是「C++26 新特性单篇精讲」系列第 4 篇。阅读约需 6 分钟,文末可跳转完整合订本。
一、是什么
C++26 允许在 constexpr 函数中使用 try/throw/catch。未捕获的编译期异常会转化为带具体错误信息的编译错误。
二、为什么需要它
此前 constexpr 函数里一旦 throw,编译器直接报错。复杂编译期算法只能用哨兵值或 static_assert(false, ...),错误信息不精确。
constexpr 异常让编译期代码的错误处理与运行时一样自然,未捕获异常还能给出更清晰的诊断。
三、完整代码示例
3.1 编译期除法
cpp
#include <stdexcept>
#include <optional>
constexpr unsigned divide(unsigned n, unsigned d) {
if (d == 0) {
throw std::invalid_argument("division by zero");
}
return n / d;
}
// 未捕获异常 → 编译错误,提示 "division by zero"
// constexpr auto a = divide(5, 0); // 编译失败
constexpr std::optional<unsigned> safe_divide(unsigned n, unsigned d) {
try {
return divide(n, d);
} catch (...) {
return std::nullopt;
}
}
constexpr auto ok = safe_divide(10, 2); // 5
constexpr auto fail = safe_divide(10, 0); // std::nullopt
static_assert(ok.value() == 5);
static_assert(!fail.has_value());
int main() {}
3.2 配置校验场景
cpp
constexpr int parse_port(int p) {
if (p <= 0 || p > 65535) {
throw std::out_of_range("port must be in [1, 65535]");
}
return p;
}
constexpr int port = parse_port(8080); // OK
// constexpr int bad = parse_port(70000); // 编译错误
四、编译器支持与特性测试宏
| 编译器 | 版本 |
|---|---|
| GCC | 15+ |
| Clang | 19+ |
| MSVC | 19.50+ |
cpp
#if __cpp_constexpr_exceptions >= 202411L
// constexpr 异常可用
#endif
五、常见陷阱
- 不能逃逸到运行时:编译期异常必须在编译期被捕获;
- 运行时调用仍正常 :
constexpr函数在运行时调用时,throw行为与往常一样; - 析构函数要求 :编译期抛出的对象必须有
constexpr析构函数。
六、小结
constexpr 异常让编译期编程拥有正常的错误处理语义,是 C++26 元编程能力的重要拼图。适合配置校验、编译期算法、模板参数检查等场景。
- 返回 C++26 新特性全景合订本 : C++26 新特性全景解析
- C/C++ 后台架构学习社区,欢迎关注: https://github.com/0voice
本文基于 C++26 已批准特性撰写,具体实现以编译器文档为准。