
在C++23中,std::expected 是一种全新的类型,用于更清晰、更安全地处理可能失败的函数调用。它提供了一种比异常和错误码更现代、更直观的方式来表达“期望得到一个值,但也可能得到一个错误”的语义。
什么是 std::expected?
std::expected
举个例子:
假设你写一个函数来解析整数:
立即学习“C++免费学习笔记(深入)”;
std::expectedparse_int(const std::string& str) { try { size_t pos; int value = std::stoi(str, &pos); if (pos != str.size()) { return std::unexpected("Invalid: extra characters"); } return value; } catch (const std::invalid_argument&) { return std::unexpected("Invalid argument"); } catch (const std::out_of_range&) { return std::unexpected("Number out of range"); } }
调用时可以这样处理结果:
auto result = parse_int("123abc");
if (result.has_value()) {
std::cout << "Got: " << *result << "\n";
} else {
std::cout << "Parse error: " << result.error() << "\n";
}
相比传统方法的优势
以往我们常用以下方式处理错误:
- 返回 bool + 输出参数(不够直观)
- 抛出异常(开销大,控制流不清晰)
- 使用 errno 或全局状态(线程不安全)
- 返回 std::pair
或 std::variant (语义模糊)
std::expected 解决了这些问题:
- 明确区分成功与失败路径
- 携带详细的错误信息(不只是 true/false)
- 零成本抽象:没有异常开销
- 编译期检查:必须处理错误,否则容易被注意到
- 支持链式操作,如 and_then、or_else 等(类似函数式编程)
如何有效使用 std::expected
实际开发中,建议这样使用:
- 对于可能失败但属于正常流程的操作(如文件读取、网络请求、数据解析),优先考虑返回 expected
- 错误类型 E 推荐使用枚举或轻量错误结构体,避免 string(除非调试需要)
- 配合 if-else 或 switch 处理分支,代码可读性强
- 利用其隐式布尔转换简化判断:
if (auto res = compute(); res) { ... }
还支持一些便捷操作:
// 链式处理
get_user_id()
.and_then(fetch_user_data)
.or_else([](const auto& e) {
log_error(e);
return default_user();
});
注意事项与现状
目前(截至主流编译器2024年版本),std::expected 在 GCC 13+、Clang 17+ 中已部分支持,需启用 -std=c++23 并注意标准库实现进度。MSVC 正在跟进。
若暂不可用,可使用 TL::expected 第三方库作为过渡,接口高度兼容。
基本上就这些。std::expected 让 C++ 的错误处理变得更直接、更可靠,是现代 C++ 值得掌握的重要工具。










