如何正确使用std::error_condition并解决自定义error_category编译错误
问题解决方案
错误1:no matching function for call to ‘std::error_condition::error_condition({anonymous}::condEnum&)’
原因
std::error_condition没有接收自定义枚举类类型的构造函数,你虽然定义了make_error_condition重载,但直接调用构造函数不会自动触发该重载。另外当前代码的switch语句没有加break,所有分支最终都会走到default逻辑,属于逻辑bug。
修复
将构造error_condition的代码改为调用你实现的make_error_condition,同时给switch分支补break:
std::error_condition ErrCategoryClass::default_error_condition(int err_value) const noexcept { condEnum oResult; switch (static_cast<errEnum>(err_value)) { case errEnum::ERR_NONE: case errEnum::ERR_A: case errEnum::ERR_B: oResult = condEnum::ERROR_CODE; break; // 补充break避免 fallthrough default: oResult = condEnum::UNKNOWN_ERROR; } return make_error_condition(oResult); // 改为调用自定义的make_error_condition }
同时需要修正message函数的数组长度判断逻辑:sizeof(aErrStrings)是数组总字节数,不是元素个数,改为:
// C++17及以上可直接用std::size,低版本用sizeof(aErrStrings)/sizeof(aErrStrings[0]) if (ev < std::size(aErrStrings))
错误2+3:specialization of ‘std::is_error_condition_enum<{anonymous}::condEnum>’ after instantiation / redefinition of ‘struct std::is_error_condition_enum<{anonymous}::condEnum>’
原因
- 你把自定义枚举、错误类别都定义在了匿名命名空间中,匿名命名空间的类型是每个翻译单元独有、对外不可见的,你在全局std命名空间对匿名空间的类型做特化,本身就违反单一定义规则(ODR),不同翻译单元会生成重复的特化定义。
- 你在std中特化类型的时机太晚:代码中先用到了
std::error_condition相关逻辑,已经触发了is_error_condition_enum的默认实例化,之后再做特化不符合C++标准要求。
修复
- 把原本放在匿名命名空间里的枚举、错误类别定义,移到自定义的具名命名空间中(比如
my_err),不能再用匿名命名空间。 - 把std的特化代码放在自定义枚举类型定义之后、任何使用
error_code/error_condition的代码之前。
示例修改后的命名空间结构:
#include <system_error> #include <iostream> #include <string> // 改用具名命名空间 namespace my_err { enum class condEnum { ERROR_CODE = 0, UNKNOWN_ERROR }; enum class errEnum { ERR_NONE = 0, ERR_A, ERR_B }; // ErrCategoryClass的定义、实现、make_error_code/make_error_condition的实现都放在这个命名空间里 } // 特化要放在枚举定义之后、使用error相关接口之前 namespace std { template <> struct is_error_condition_enum<my_err::condEnum> : public true_type {}; template <> struct is_error_code_enum<my_err::errEnum> : public true_type {}; } // 后续写main等业务逻辑
整体实现评估
你自定义std::error_category的核心思路是正确的,只需要修正上述几个语法、逻辑、命名空间的细节问题,代码就能正常编译运行。
内容的提问来源于stack exchange,提问作者Palenty
相关产品推荐
相关产品推荐

