std::expected 仅适用于同步结果管道,不支持异步调度或等待;其 and_then/or_else 为立即求值的类型安全转换,异步组合需依赖 std::future 或协程配合自定义 awaiter。

std::expected 不能直接用于异步流,别硬套
它不是 std::future 或 std::coroutine_handle 的替代品,也没有内置调度、等待或链式转发能力。强行用 std::expected<T, E> 包裹异步结果(比如把 std::future<std::expected<int, std::error_code>> 当“组合式流”用),只会让错误传播变隐晦、取消逻辑丢失、执行时机不可控。
真正能组合的只有 std::expected 的值转换逻辑
它的价值在同步上下文里的“结果管道”:拿到一个 std::expected<T, E> 后,用 and_then / or_else 做类型安全的链式转换,类似 Rust 的 ? 或 Haskell 的 >>=。但这些函数本身不触发异步操作,也不处理线程切换。
-
and_then接收一个返回std::expected<U, E>的函数,成功时调用并返回新预期值 -
or_else在失败时调用,参数是E&,返回另一个std::expected<T, F> - 所有操作都是立即求值的——没有延迟、没有 await、不涉及 executor
想组合异步操作?得靠 std::future + 手动适配 expected
典型做法是把异步任务封装成返回 std::future<std::expected<T, E>> 的函数,再用 std::async 或 executor 提交;组合则靠手动 then(C++20 没标准 then,需用 std::future::wait_for + 回调模拟,或依赖第三方如 boost::asio::awaitable)。
示例片段(简化版):
立即学习“C++免费学习笔记(深入)”;
auto load_config() -> std::future<std::expected<Config, std::error_code>> {
return std::async(std::launch::async, []() -> std::expected<Config, std::error_code> {
if (auto ec = read_file("config.json", ...)) return unexpected(ec);
return parse_config(...);
});
}
// 组合:必须显式 .get() 或 co_await(若用协程)
auto run() -> std::future<std::expected<Result, std::error_code>> {
return std::async(std::launch::async, []() {
auto cfg = load_config().get(); // 阻塞获取
if (!cfg) return std::unexpected(cfg.error());
return process(cfg.value());
});
}
协程是目前最接近“组合式异步异常流”的可行路径
C++20 协程 + std::expected 才能逼近你想要的效果:用 co_await 等待异步操作,用 co_return std::expected<...> 统一成功/失败出口,再靠 co_await 自动传播错误(前提是 awaiter 正确处理 std::expected 的 error 分支)。
关键点:
- awaiter 的
await_resume()必须检查std::expected是否有值,否则co_await会崩溃或静默忽略错误 - 不能直接
co_await一个std::future<std::expected<...>>—— 它没定义对应 awaiter,得自己写或用boost::asio::use_awaitable - 协程栈上无法自动传播
std::expected错误到调用方,必须显式co_return std::unexpected(...)
真正难的不是语法,是把 executor、取消信号、超时、错误分类这些都对齐到 std::expected 的 error 类型上——没人能绕开这层设计权衡。


















