需要宏来对枚举进行字符串化,并有助于避免std中专门化的样板文件,但是可以提取一些代码来创建模板:
// Traits to retrieve name and mapping from enum.
template <typename E>
struct enum_traits
{
static_assert(std::is_enum<E>::value, "!");
static const char* const name;
static const std::map<E, std::string> mapping;
};
template <typename E>
struct ECategory_impl : std::error_category
{
static_assert(std::is_enum<E>::value, "!");
const char* name() const noexcept override
{
return enum_traits<E>::name;
}
std::string message(int c) const override
{
const auto& Map = enum_traits<E>::mapping;
E code = static_cast<E>(c);
auto itr = Map.find(code);
if (itr != Map.end())
{
return itr->second;
}
else
{
return "(unrecognized error)";
}
}
};
template <typename E>
std::error_code make_error_code(E e)
{
static_assert(std::is_enum<E>::value, "!");
static const ECategory_impl<E> categ{};
return {static_cast<int>(e), categ};
}
然后是宏(如果您认为现在要重复的内容足够少,可以忽略这个宏):
#define MAKE_ERROR_CODE_CATEGORY(E) \
/* Stringification for the name*/ \
template <> const char* const enum_traits<E>::name = #E; \
/* Specialization in std */ \
namespace std \
{ \
template <> \
struct is_error_code_enum<E> : true_type {}; \
} \
/* Alias for custom naming */ \
using E##_category = ECategory_impl<E>;
// ^
// You might remove that final ';' for a usage `MAKE_ERROR_CODE_CATEGORY(E);`
// instead of current `MAKE_ERROR_CODE_CATEGORY(E)`
用法类似于:
enum class E {A, B};
template <>
const std::map<E, std::string> enum_traits<E>::mapping{
{E::A, "A"},
{E::B, "E"}
};
MAKE_ERROR_CODE_CATEGORY(E)
Demo