c++23 std::expected怎么用 c++优雅处理函数错误返回【详解】

15次阅读

std::expected 是 c++23 引入的值优先、错误显式的标准化错误处理工具,用于替代返回码或自定义包装类型,适用于文件解析、配置读取等可预期失败场景,不取代异常。

c++23 std::expected怎么用 c++优雅处理函数错误返回【详解】

std::expected 是 C++23 引入的标准化错误处理工具,用来替代传统返回码、异常或自定义包装类型(如 std::optional + 状态码),实现“值优先、错误显式”的函数返回风格。它不是万能异常替代品,而是为预期可能失败但不属异常语义的场景(比如文件解析、配置读取、网络响应解码)提供更清晰、更安全、更可组合的返回接口

std::expected 的基本结构和构造方式

模板形式为 std::expected,其中 T 是成功时携带的值类型E 是失败时携带的错误类型(通常为 std::Error_codestd::String 或自定义错误枚举)。它内部只保存 TE 中的一个,不可同时存在。

  • 成功构造:std::expected ok{42};std::make_expected(42);
  • 失败构造:std::expected err{std::unexpect, "file not found"};std::make_unexpected("timeout");
  • 检查状态:if (res.has_value()) { /* 成功 */ } else { /* 失败,用 res.error() 取错误 */ }

链式调用与错误传播:用 and_then / transform 处理成功路径

当多个操作需按顺序执行、且任一环节失败就终止并透传错误时,and_then 是核心工具。它只在当前为 value 时调用传入的函数,并自动将该函数返回的 expected “扁平化”——避免嵌套 expected,E>

  • auto res = parse_json(str).and_then(validate_schema).and_then(extract_user_id);
  • 每个函数都返回 std::expected,类型需兼容(错误类型最好一致)
  • 若某步返回 unexpected,后续函数不执行,整个链直接返回该错误

错误转换与兜底处理:用 or_else 和 value_or

当需要对特定错误做修复、降级或日志记录时,or_else 接收一个以 const E& 为参数的函数,返回新的 expected;而 value_or 提供简单默认值兜底(仅适用于可默认构造或提供默认值的 T)。

立即学习C++免费学习笔记(深入)”;

  • auto id = fetch_user_id().or_else([](const std::error_code& ec) { return fallback_user_id(); });
  • int timeout = get_timeout_config().value_or(3000); // 失败时用 3000
  • 注意:value_or 会强制移动或拷贝 T,若 T 构造代价高或不可拷贝,应改用 and_then + 显式判断

与异常、optional 的关键区别和使用边界

std::expected 不取代异常,也不等价于 std::optional

  • 异常用于真正意外、无法局部恢复的错误(如内存耗尽、硬件故障);expected 用于业务逻辑中可预见、可分类处理的失败(如“用户不存在”、“配置缺失”)
  • std::optional 只能表达“有/无值”,无法携带错误原因;expected 明确区分“成功值”和“失败原因”,支持错误类型多态和模式匹配(配合 std::visit 自定义访问器
  • 函数签名更自文档化:expected parse(const std::string&)bool parse(..., Data& out) 或抛异常更直观、更易组合

不复杂但容易忽略:别把所有函数都改成 expected,优先用于 I/O、解析、校验等天然带失败语义的函数;保持错误类型轻量、可比较、可输出;搭配 std::error_code + std::system_category() 或自定义错误类别,能更好融入系统生态。

text=ZqhQzanResources