如何在catch站点遍历boost::exception的所有error_info元素?
当然可以实现!完全不用重复造轮子
其实Boost异常库本身就提供了遍历所有error_info元素的机制,比解析boost::diagnostic_information的输出要可靠得多。下面是具体的实现思路和代码示例:
核心思路
Boost的error_info是通过类型标签绑定到boost::exception上的,我们可以用boost::exception::visit函数来遍历所有附加的error_info元素,再通过自定义的**访问器(visitor)**来提取每个元素的名称和值——这和boost::diagnostic_information内部的实现逻辑是一致的,只是我们把它拆出来单独收集键值对而已。
具体实现步骤
1. 定义一个错误信息收集器(Visitor)
这个访问器会被boost::exception::visit调用,处理每个error_info元素:
#include <boost/exception/all.hpp> #include <string> #include <vector> #include <sstream> #include <iostream> struct ErrorInfoCollector { // 用来存储提取到的名称-值对 mutable std::vector<std::pair<std::string, std::string>> entries; // 模板方法,匹配任意类型的error_info template <typename ErrorInfoType> void operator()(ErrorInfoType const& ei) const { // 获取error_info的官方名称(比如errinfo_errno的名称是"errno") std::string info_name = ei.name(); // 将值转换为字符串(和diagnostic_information的输出逻辑一致) std::ostringstream value_stream; value_stream << ei.value(); // 存入键值对 entries.emplace_back(info_name, value_stream.str()); } };
2. 在Catch块中遍历并收集信息
捕获异常后,先尝试将其转换为boost::exception类型,然后用visit函数触发遍历:
try { // 示例:抛出一个带多个error_info的异常 throw boost::enable_error_info(std::runtime_error("Failed to read file")) << boost::errinfo_file_name("config.json") << boost::errinfo_errno(ENOENT) << boost::errinfo_line_number(42); } catch (std::exception const& e) { // 检查是否是Boost包装过的异常 if (auto boost_exc = dynamic_cast<boost::exception const*>(&e)) { ErrorInfoCollector collector; // 遍历所有error_info元素,收集键值对 boost::exception::visit(*boost_exc, collector); // 输出收集到的结果 std::cout << "提取到的异常信息键值对:\n"; for (auto const& [name, value] : collector.entries) { std::cout << "- *" << name << "*: " << value << "\n"; } // 同时也可以保留diagnostic_information的完整输出 std::cout << "\n完整诊断信息:\n" << boost::diagnostic_information(e) << "\n"; } else { // 普通std::exception,没有附加error_info std::cout << "标准异常: " << e.what() << "\n"; } }
关键细节说明
- 类型安全的遍历:
boost::exception::visit会自动匹配每个error_info的类型,不需要我们手动判断,避免了类型转换错误。 - 和diagnostic_information保持一致:通过
ei.name()获取官方名称,用流输出值,确保和boost::diagnostic_information的输出内容完全一致,不需要重复实现格式化逻辑。 - 兼容普通std::exception:如果捕获的异常没有被
boost::enable_error_info包装,dynamic_cast会返回nullptr,这时候就按普通异常处理即可。
内容的提问来源于stack exchange,提问作者Pat
相关产品推荐
相关产品推荐

