std::expected 是 C++23 引入的值或错误二选一的类模板,语义明确、零成本、需显式处理;支持 and_then/or_else 链式调用,区别于 optional(无错误上下文)和异常(非预期错误),适用于 I/O、解析等常规可恢复错误场景。

std::expected 是 C++23 引入的标准库新类型,用于明确区分成功结果与错误信息,替代传统上用返回值+全局 errno、异常、或自定义 pair/variant 的做法。它不是“可选值”,而是“预期得到某个值,否则得到一个错误”——语义更清晰,调用方必须显式处理两种可能。
核心设计:值 or 错误,二者必居其一
std::expected
- 构造时直接指定值:
std::expected<int std::string> result{42};</int> - 构造错误:
std::expected<int std::string> err{std::unexpect, "file not found"};</int> - 检查状态:
if (result.has_value()) { /* 成功 */ } else { /* 处理 result.error() */ }
链式调用:用 and_then、or_else 实现无异常的管道流
std::expected 支持类似 Rust Result 的组合操作,让多个可能失败的操作自然串联,避免层层嵌套 if 判断。
-
and_then:当前成功时执行函数,该函数也返回 expected;失败则短路,保留原错误 -
or_else:当前失败时执行函数,用于错误恢复或转换
例如:
auto res = read_config()<br>
.and_then(parse_config)<br>
.and_then(validate_config)<br>
.or_else([](const auto& e) { return fallback_config(); });整条链要么返回最终配置,要么返回 fallback 或原始错误,逻辑平铺直叙。
与异常、optional 的关键区别
不是 std::optional 的替代品:optional 表示“可能没有值”,但不说明“为什么没有”;expected 明确携带错误上下文,适合系统级 I/O、解析、校验等有丰富失败原因的场景。
不是异常的替代品:异常适合意外、不可恢复的错误(如内存耗尽);expected 适合预期中可能发生的常规错误(如文件不存在、JSON 格式错误),调用方应主动检查而非放任传播。
立即学习“C++免费学习笔记(深入)”;
- 性能确定:无栈展开开销,适合实时或嵌入式环境
- 接口契约清晰:函数签名即表明“可能失败”,调用者无法忽略错误分支
- 可与异常共存:你仍可在 expected 内部使用 throw,但推荐统一风格
实际使用建议
从 C++23 开始,优先在新接口中用 std::expected 替代 “int 返回码 + out 参数” 或 “throw std::runtime_error”。尤其适用于:
- 文件读写、网络请求、配置加载等 I/O 操作
- 字符串解析(JSON、URL、日期)、数值转换(stoi 安全版)
- 工厂函数、构造辅助函数(当构造逻辑可能失败时)
注意:目前主流编译器(GCC 13+、Clang 16+、MSVC 19.35+)已支持,需开启 -std=c++23。标准库实现基于 <expected> 头文件,无需第三方依赖。











