我正在尝试编写一个宏,它可以帮助构建具有各种辅助函数的enum class
,例如转换为字符串。在某种集合中提供对enum的所有值的访问是很自然的:
DEFINE_ENUM(Foo, Value1, Value2);
for (Foo v : enum_traits<Foo>::all_values) {
// ...
}
似乎可以通过使DEFINE_ENUM()
宏专门化一个公共enum_traits
类来实现:
// globally:
template<typename T> struct enum_traits {};
// inside the macro:
#define DEFINE_ENUM(Name, ...) \
/* define "enum class Name" ... */ \
template<> struct my_enum_traits<Name> { \
/* define all_values member */ \
};
但是,如果DEFINE_ENUM(Foo, Value1, Value2);
的扩展发生在命名空间内,那么它似乎不可能从该命名空间外部专门化模板:
template<typename T> struct enum_traits {};
namespace foo {
// imagine DEFINE_ENUM is invoked here:
enum class Foo { Value1, Value2 };
// error: class template specialization of 'enum_traits'
// must occur at global scope
template<> struct ::enum_traits<Foo> { /* ... */ };
}
有没有办法实现这一点,即宏可以“转义”包含其调用的命名空间,并从不同的命名空间(甚至是全局命名空间)中专门化一个模板?
答案 0 :(得分:3)
好吧,我不能直接帮助这个特质模板专业化问题,我怀疑这是不可能的。
但是可以通过ADL
实现您的真正目标见诀窍:
// globally:
template<typename T>
using enum_traits = decltype(get_enum_traits(T{}));
诀窍是在get_enum_traits
的命名空间中定义函数T
。此函数应具有返回类型 - 应该是您的特征的类型。这个函数不需要实现 - 只有ADL方式从新定义的枚举类型的命名空间中获取类型。
// inside the macro:
#define DEFINE_ENUM(Name, ...) \
/* define "enum class Name" ... */ \
enum class Name { __VA_ARGS__ }; \
struct Name##_type_traits { \
/* define all_values member */ \
}; \
Name##_type_traits get_enum_traits(Name);
有些demo确实有效。
#include <array>
// globally:
template<typename T>
using enum_traits = decltype(get_enum_traits(T{}));
// inside the macro:
#define DEFINE_ENUM(Name, ...) \
/* define "enum class Name" ... */ \
enum class Name { __VA_ARGS__ }; \
struct Name##_type_traits { \
static constexpr std::array<Name,1> values{{ Name{} }}; \
}; \
Name##_type_traits get_enum_traits(Name); // does not need implementation
namespace foo {
DEFINE_ENUM(Foo, Value1, Value2);
}
int main( ) {
for (auto e: enum_traits<foo::Foo>::values)
{}
}