如何用C++23的std::expected及transform_error处理stoi抛出的错误?
用std::expected实现无try-catch的字符串转整数错误处理
先直接说结论:原生std::stoi没法直接配合std::expected实现无try-catch的错误处理——因为std::stoi本身是靠抛出异常报告错误的,而std::expected是基于返回值的「铁路式」错误处理模型。要达成你要的效果,得先封装一个不抛异常的字符串转整数函数,再结合std::expected和transform_error来处理错误。
具体实现步骤
1. 封装非抛出式的字符串转整数函数
C++17引入的std::from_chars是无异常的字符串转数值工具,它返回std::from_chars_result,其中包含转换是否成功的状态(ec字段,类型为std::error_code)。我们可以基于它封装一个返回std::expected<int, std::error_code>的函数:
#include <string> #include <expected> #include <charconv> #include <system_error> std::expected<int, std::error_code> stoi_noexcept(std::string_view s) { int value; auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), value); if (ec == std::errc()) { // 转换成功,返回整数值 return value; } else { // 转换失败,返回错误码 return std::unexpected(ec); } }
2. 用std::expected和transform_error处理错误
有了非抛出式的函数后,就可以用std::expected的链式调用(包括transform_error)实现铁路式错误处理,全程不需要try-catch:
#include <iostream> void handleInput(char* argv[]) { stoi_noexcept(argv[1]) // 把error_code转换成可读性高的错误信息字符串 .transform_error([](std::error_code ec) -> std::string { if (ec == std::errc::invalid_argument) { return "invalid argument: 无法将输入转换为整数"; } else if (ec == std::errc::result_out_of_range) { return "out of range: 输入值超出整数范围"; } else { return "unknown error: " + ec.message(); } }) // 处理转换成功的逻辑 .and_then([](int value) -> std::expected<void, std::string> { std::cout << "转换成功,值为: " << value << std::endl; return {}; }) // 处理错误逻辑 .or_else([](std::string err_msg) -> std::expected<void, std::string> { std::cerr << err_msg << std::endl; return std::unexpected(std::move(err_msg)); }); } int main(int argc, char* argv[]) { if (argc < 2) { std::cerr << "请提供一个字符串参数" << std::endl; return 1; } handleInput(argv); return 0; }
关键说明
transform_error的核心作用是将std::expected中的错误类型转换为更适合后续处理的类型(这里从std::error_code转为std::string),实现错误信息的统一格式化。- 之所以不能直接用原生
std::stoi,是因为它的错误报告机制是抛出异常而非返回错误状态。如果硬要结合std::expected,必须先用try-catch捕获异常再塞进std::unexpected,这就无法避免try-catch块,不符合你的需求。 std::from_chars是专门为错误处理优化的工具,它的设计完全基于返回值报告状态,完美匹配std::expected的使用场景。
内容的提问来源于stack exchange,提问作者NicholasCostanza
相关产品推荐
相关产品推荐

