c++oding="utf-8" ?>
and_then本质是flatmap,接收返回std::expected的函数,成功时传值并展平,失败时短路;or_else仅在错误时调用,返回同value_type的expected;链式调用需严格保持value_type和error_type一致性。

and_then 本质是 flatMap,不是 map
and_then 接收一个返回 std::expected 的函数,把当前成功值传进去,再“展平”一层嵌套。如果当前是错误,就直接短路返回原 std::expected,不调用函数。
常见错误是传入返回普通值(比如 int 或 std::string)的 lambda,编译失败报错类似:no matching function for call to 'and_then' —— 因为类型不匹配,and_then 要求返回另一个 std::expected。
- ✅ 正确写法:
e.and_then([](int x) { return std::expected<int std::string>(x * 2); })</int> - ❌ 错误写法:
e.and_then([](int x) { return x * 2; })(返回int,不是expected) - ⚠️ 注意:返回的
expected类型必须和原始对象的error_type一致,否则编译不过(例如原始是expected<int std::errc></int>,就不能在and_then里返回expected<double std::string></double>)
or_else 处理错误分支,但只在 has_value() == false 时触发
or_else 接收一个以 error_type 为参数、返回 std::expected 的函数。它不处理成功值,只在当前对象处于错误状态时才调用该函数。
容易踩的坑是误以为它像 catch 那样“兜底”,结果发现成功路径被吞掉或逻辑跳过。比如:e.or_else([](auto err) { return std::expected<int std::string>("fallback"); })</int> —— 如果 e 是成功的,整个表达式还是原 e,不会变成 fallback 值。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- ✅ 典型用途:错误恢复,如重试、降级、转换错误类型:
e.or_else([](std::errc e) { return std::expected<int std::string>(std::make_error_code(e).message()); })</int> - ⚠️ 返回的
expected必须和原对象的value_type一致(成功值类型),否则无法参与链式调用 - ⚠️ 不要试图在
or_else里返回std::unexpected—— 它只接受返回expected的函数,返回unexpected会导致类型推导失败
链式组合 and_then / or_else 的顺序决定控制流走向
链式调用不是任意排列都等价的。and_then 在前会优先处理成功路径,中间出错就终止;or_else 在前则先检查错误,但若它返回成功值,后续 and_then 仍可继续处理。
示例:读配置 → 解析整数 → 默认值兜底
auto res = read_config("timeout")
.and_then([](std::string s) -> std::expected<int std::string> {
try { return std::stoi(s); }
catch (...) { return std::unexpected("invalid number"); }
})
.or_else([](std::string err) -> std::expected<int std::string> {
return std::expected<int std::string>(30); // 默认 30 秒
});
</int></int></int>
- ✅ 这里
or_else把解析失败转为默认值,且返回的是expected<int ...></int>,所以能继续被后续and_then消费(如果还有) - ⚠️ 如果把
or_else放最前面,而read_config成功了,or_else根本不执行,后续逻辑照常;但如果它失败了,or_else返回成功值,那整个链就“变成功”了 —— 控制流语义和你放的位置强相关 - ⚠️ 链中任一环节返回的
expected的error_type必须兼容,否则模板实例化失败(比如前面用std::errc,后面or_else返回std::string错误,类型不匹配)
实际项目中容易忽略的兼容性细节
C++23 的 std::expected 在不同标准库实现中仍有细微差异,尤其是 MSVC 的 STL 和 libstdc++ 对 and_then/or_else 的 SFINAE 处理更严格。
- ✅ GCC 13+ / Clang 16+ + libc++ 17+ 支持完整 C++23 行为
- ⚠️ 使用 Clang 编译时若链接 libstdc++(而非 libc++),可能遇到
and_then未定义 —— 因为旧版 libstdc++ 尚未实现这些扩展 - ⚠️
and_then和or_else都是 const 成员函数,但它们的参数函数可以是 mutable lambda;不过一旦你在 lambda 里修改了外部状态,要注意是否符合预期的副作用时机(比如错误分支根本没执行,状态就没变) - ⚠️ 不要依赖移动语义自动优化:如果
and_then内部构造的expected含大对象,显式用std::move包裹返回值更安全(尤其在 debug 模式下)
链式调用看着简洁,但每一步的类型契约和短路逻辑都得对得上,否则编译器报错信息往往藏在十几层模板栈里,盯住 error_type 和 value_type 的一致性最省时间。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










