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