std::expected 仅适用于同步结果管道,不支持异步调度或等待;其 and_then/or_else 为立即求值的类型安全转换,异步组合需依赖 std::future 或协程配合自定义 awaiter。
它不是 std::future 或 std::coroutine_handle 的替代品,也没有内置调度、等待或链式转发能力。强行用 std::expected<T, E> 包裹异步结果(比如把 std::future<std::expected<int, std::error_code>> 当“组合式流”用),只会让错误传播变隐晦、取消逻辑丢失、执行时机不可控。
它的价值在同步上下文里的“结果管道”:拿到一个 std::expected<T, E> 后,用 and_then / or_else 做类型安全的链式转换,类似 Rust 的 ? 或 Haskell 的 >>=。但这些函数本身不触发异步操作,也不处理线程切换。
and_then 接收一个返回 std::expected<U, E> 的函数,成功时调用并返回新预期值or_else 在失败时调用,参数是 E&,返回另一个 std::expected<T, F>
典型做法是把异步任务封装成返回 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 分支)。
关键点:
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 类型上——没人能绕开这层设计权衡。