如何在C++中实现编译期生成唯一错误码并映射到字符串?
C++编译期唯一错误码分配与映射实现方案
C++20及以上完全支持你需求的编译期错误码分配与字符串映射功能,以下是几种实用方案,以及类级错误处理的替代建议:
方案1:利用编译器扩展__COUNTER__(简单高效)
主流编译器(GCC/Clang/MSVC)都支持__COUNTER__宏,它会在每次调用时生成递增的唯一整数,结合constexpr数组可实现编译期的错误信息映射:
核心代码
#include <cstdint> #include <string_view> #include <array> #include <utility> // 声明类级错误:生成唯一错误码和对应信息条目 #define DECLARE_CLASS_ERROR(class_name, error_name, msg) \ namespace class_name##_errors { \ inline constexpr uint32_t error_name = __COUNTER__; \ inline constexpr std::pair<uint32_t, std::string_view> error_name##_entry = {error_name, msg}; \ } \ using namespace class_name##_errors; // 收集所有错误条目,需在全局cpp文件中调用 #define COLLECT_ALL_ERRORS(...) \ inline constexpr std::array<std::pair<uint32_t, std::string_view>, sizeof...(__VA_ARGS__)> g_error_entries = {__VA_ARGS__}; // 编译期错误信息查找函数 constexpr std::string_view error_str(uint32_t code) { for (const auto& entry : g_error_entries) { if (entry.first == code) { return entry.second; } } return "Unknown error code"; }
使用示例
my_class.h:
class MyClass { public: DECLARE_CLASS_ERROR(MyClass, MYERROR, "Myerror message"); DECLARE_CLASS_ERROR(MyClass, MYOTHERERROR, "Myothererror message"); int my_func(int input) { if (input < 0) { return -static_cast<int>(MYERROR); } return 0; } };
somewhere_else.h:
class SomewhereElse { public: DECLARE_CLASS_ERROR(SomewhereElse, ANOTHER_ERROR, "Another_error message"); };
全局cpp文件(如error_registry.cpp):
#include "my_class.h" #include "somewhere_else.h" COLLECT_ALL_ERRORS( MyClass_errors::MYERROR_entry, MyClass_errors::MYOTHERERROR_entry, SomewhereElse_errors::ANOTHER_ERROR_entry );
方案2:纯标准C++20模板元编程(无编译器扩展)
如果需要完全依赖标准C++,可以用模板元编程实现编译期计数器:
核心代码
#include <cstdint> #include <string_view> #include <array> #include <type_traits> namespace error_detail { // 每个唯一Tag对应一个递增的错误码 template <typename Tag> struct ErrorCounter { inline static constexpr uint32_t value = []{ static uint32_t cnt = 0; return cnt++; }(); }; // 存储错误信息的模板特化 template <typename Tag> struct ErrorInfo {}; // 生成错误信息数组 template <typename... Tags> constexpr auto make_error_array() { return std::array<std::pair<uint32_t, std::string_view>, sizeof...(Tags)>{ {ErrorCounter<Tags>::value, ErrorInfo<Tags>::msg}... }; } } // 注册错误:生成唯一Tag类型 #define REGISTER_ERROR(error_name, msg) \ struct error_name##_Tag {}; \ template <> \ struct error_detail::ErrorInfo<error_name##_Tag> { \ inline static constexpr std::string_view msg = msg; \ }; \ inline constexpr uint32_t error_name = error_detail::ErrorCounter<error_name##_Tag>::value; // 初始化全局错误注册表 #define INIT_ERROR_REGISTRY(...) \ inline constexpr auto g_error_entries = error_detail::make_error_array<__VA_ARGS__>(); // 编译期错误信息查找 constexpr std::string_view error_str(uint32_t code) { for (const auto& entry : g_error_entries) { if (entry.first == code) { return entry.second; } } return "Unknown error code"; }
使用示例
my_class.h:
class MyClass { public: REGISTER_ERROR(MYERROR, "Myerror message"); REGISTER_ERROR(MYOTHERERROR, "Myothererror message"); int my_func(int input) { if (input < 0) { return -static_cast<int>(MYERROR); } return 0; } };
全局cpp文件:
#include "my_class.h" #include "somewhere_else.h" INIT_ERROR_REGISTRY( MYERROR_Tag, MYOTHERERROR_Tag, ANOTHER_ERROR_Tag );
类级错误处理的简化建议
如果项目复杂度不高,以下方案更易维护:
方案:枚举类+编译期switch
给每个类分配独立的错误码区间,用枚举类封装,通过switch实现编译期错误信息查找:
class MyClass { public: enum class Error : uint32_t { MYERROR = 1000, // 给MyClass分配1000-1999区间 MYOTHERERROR = 1001 }; static constexpr std::string_view error_str(Error err) { switch(err) { case Error::MYERROR: return "Myerror message"; case Error::MYOTHERERROR: return "Myothererror message"; default: return "Unknown MyClass error"; } } int my_func(int input) { if (input < 0) { return -static_cast<int>(Error::MYERROR); } return 0; } };
方案:标准库std::error_code
适合大型项目,符合C++标准错误处理范式,支持运行期扩展:
#include <system_error> #include <string_view> class MyClassErrorCategory : public std::error_category { public: const char* name() const noexcept override { return "MyClassError"; } std::string message(int ev) const override { switch(static_cast<uint32_t>(ev)) { case 1000: return "Myerror message"; case 1001: return "Myothererror message"; default: return "Unknown MyClass error"; } } }; inline const MyClassErrorCategory& my_class_error_category() { static MyClassErrorCategory cat; return cat; } enum class MyClassError : uint32_t { MYERROR = 1000, MYOTHERERROR = 1001 }; inline std::error_code make_error_code(MyClassError err) { return {static_cast<int>(err), my_class_error_category()}; } namespace std { template<> struct is_error_code_enum<MyClassError> : true_type {}; } // 使用方式 int MyClass::my_func(int input) { if (input < 0) { return static_cast<int>(MyClassError::MYERROR); // 或返回标准error_code:return make_error_code(MyClassError::MYERROR); } return 0; }
内容的提问来源于stack exchange,提问作者magnusmaehlum
相关产品推荐
相关产品推荐

