跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

c++23的std::expected的monadic接口是什么? (and_then, or_else)

std::expected 的 and_then 是 monadic 绑定操作:仅当含值时调用函数并返回新 expected,error 状态则透传;函数参数须为值类型 T,返回值必须是 std::expected(值类型任意、error 类型可变),不支持隐式转换。 std::expected 的
and_then
是什么行为?
and_then
是
std::expected
(C++23)提供的 monadic 绑定操作:它只在对象处于“含值”状态(即
has_value() == true
)时,调用你传入的函数,并将该函数的返回值作为新的
std::expected
返回;如果当前是 error 状态,则直接透传原 error,不执行函数。 关键点: 函数参数类型必须是
T
(即
expected
的值类型),不能是引用或 const 限定——标准要求按值捕获,避免生命周期问题 函数返回类型必须是另一个
std::expected
(可为不同 error 类型,但值类型任意) 不支持 隐式转换 ;若函数返回
expected
,而你当前是
expected
,编译器不会自动转成
expected
—— error 类型不兼容会直接编译失败
std::expected maybe_int = 42; auto next = maybe_int.and_then([](int x) { return std::expected{x * 1.5}; }); // next 是 expected
std::expected 的
or_else
什么时候触发?
or_else
是 error 分支的 monadic 对应物:仅当
has_value() == false
时才调用你传入的函数,且该函数必须接收 error 类型(
E
)并返回另一个
std::expected
(值类型必须一致,error 类型可变)。 常见误用: 立即学习 “ C++免费学习笔记(深入) ”; 传入函数签名错误,比如写成
[](int err) { ... }
而实际 error 类型是
std::errc
→ 编译失败 返回类型值类型不匹配:当前是
expected
,但
or_else
函数返回
expected
→ 编译失败(T 必须相同) 试图在
or_else
里抛异常:虽然语法允许,但违背 monadic 错误处理契约,应统一用 error 值传递
std::expected maybe_str = std::unexpected{123}; auto recovered = maybe_str.or_else([](int err) -> std::expected { if (err == 123) return "fallback"; return std::unexpected{err}; });
and_then / or_else 的组合链与类型推导陷阱 连续使用
and_then
和
or_else
时,每个环节都严格检查返回类型的
T
和
E
是否可拼接。编译器不会帮你做 error 类型归一化 —— 比如前一步返回
expected
,下一步
or_else
期望处理
int
,就断链了。 php版微信js-sdk支付接口类 php版微信js-sdk支付接口类 下载 实用建议: 用
auto
接收中间结果,避免手动写嵌套模板名(尤其 error 类型长时) 若需统一 error 类型,提前用
std::variant
或自定义 tag 类型封装多种错误,再让所有
or_else
分支返回同一种
E
注意移动语义:传入的 lambda 若捕获大对象,
and_then
内部会 move 调用,确保 lambda 可移动(或用值捕获而非引用) 和传统 if-else 相比,monadic 接口的实际价值在哪? 不是为了炫技,而是解决「深层嵌套错误传播」问题。比如解析 JSON → 提取字段 → 转整数 → 校验范围,每步都可能失败。用 if-else 易写成四层缩进;用
and_then
可扁平表达,且天然短路(任一环节 error 就终止后续)。 但要注意: 调试困难:堆栈里看不到中间
and_then
的具体哪步失败,error 值被透传,需靠日志或包装器注入上下文 无法中途修改 error 类型而不显式转换:比如想把
std::filesystem::error_code
转成自定义
ParseError
,必须在
or_else
里手动构造
unexpected
不支持「同时处理 success 和 error」的双分支逻辑(那是
transform
+
map_error
的事,不是 monadic 接口职责) 真正复杂的错误恢复流程,往往需要
and_then
、
or_else
和
transform
混用,而不是只押注某一个。

相关文章