std::expected<int, std::string> safe_divide(int a, int b){ if (b == 0) return std::unexpected("division by zero"); return a / b; }
std::expected<int, std::string> parse_int(std::string_view sv){ int value{}; auto [ptr, ec] = std::from_chars(sv.data(), sv.data() + sv.size(), value); if (ec == std::errc{}) return value; return std::unexpected("parse error"); }
intmain(){ auto r1 = safe_divide(10, 2); if (r1.has_value()) std::cout << "10/2 = " << *r1 << "\n"; auto r2 = safe_divide(10, 0); if (!r2) std::cout << "error: " << r2.error() << "\n"; std::cout << r2.value_or(0) << "\n"; auto r3 = parse_int("42"); if (r3) std::cout << "parsed: " << *r3 << "\n"; // monadic chain (C++23) auto result = parse_int("123").transform([](int n) { return n * 2; }); if (result) std::cout << "doubled: " << *result << "\n"; }
输出:
1 2 3 4 5
10/2 = 5 error: division by zero 0 parsed: 42 doubled: 246
四、实际应用场景
场景 1:配置解析器
1 2 3 4 5 6 7 8 9
std::expected<Config, std::string> parse_config(const std::string& path){ auto content = read_file(path); if (!content) return std::unexpected("cannot read file"); auto json = parse_json(*content); if (!json) return std::unexpected("invalid JSON: " + json.error()); return Config::from_json(*json); }
场景 2:网络请求
1 2 3 4 5 6 7 8 9
std::expected<Response, NetworkError> fetch_url(const std::string& url){ auto conn = connect(url); if (!conn) return std::unexpected(conn.error()); auto data = conn->read(); if (!data) return std::unexpected("timeout"); returnparse_response(*data); }
场景 3:链式验证
1 2 3 4 5 6 7
auto result = parse_int(user_input) .and_then([](int n) { return (n >= 0 && n <= 100) ? std::expected<int, std::string>(n) : std::unexpected("out of range"); }) .transform([](int n) { return n * 10; });
五、三种错误处理方式对比
维度
Exception
std::optional
std::expected
错误原因
✅ 可携带
❌ 不能携带
✅ 可携带
性能开销
⚠️ 有开销
✅ 零开销
✅ 零开销
链式调用
❌ 需 try/catch
⚠️ 有限支持
✅ 完全支持
嵌入式友好
❌ 否
✅ 是
✅ 是
调用链可读性
✅ 好
⚠️ 需手动检查
✅ 好
编译器优化
⚠️ 可能被抑制
✅ 完全优化
✅ 完全优化
六、何时选用 std::expected?
优先使用 std::expected 的场景:
性能关键路径(游戏引擎、嵌入式、实时系统)
错误原因需要传递给上层调用者
需要链式处理多个可能失败的步骤
不希望引入异常处理的运行时开销
仍考虑异常的场景:
极端不可恢复的错误(内存分配失败、栈溢出)
需要跨越大量调用栈传播
团队已经深度依赖异常机制
总结:std::expected 是 C++ 错误处理的”最优解”——它兼具错误码的零开销和异常的表达力,同时支持优雅的链式调用。如果你还在用 std::optional + 错误码组合,或者过度使用异常,建议逐步迁移到 std::expected。