声明是否有可能转义其封闭的命名空间?

jtb*_*des 5 c++ namespaces

我正在尝试编写一个宏来帮助构建enum class具有各种帮助函数的宏,例如用于转换为字符串。在某种集合中提供对枚举的所有值的访问是很自然的:

DEFINE_ENUM(Foo, Value1, Value2);

for (Foo v : enum_traits<Foo>::all_values) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

这似乎可以通过使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 */ \
    };
Run Code Online (Sandbox Code Playgroud)

但是,如果扩展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> { /* ... */ };
}
Run Code Online (Sandbox Code Playgroud)

有什么方法可以实现这一点,即让宏“转义”包含其调用的命名空间,并从不同的命名空间(甚至全局命名空间)专门化一个模板?

Pio*_*ycz 5

好吧,我无法直接帮助解决这个特征模板专业化问题,我怀疑这是不可能的。

但通过ADL实现您的真正目标是可能的

看窍门:

// globally:
template<typename T> 
using enum_traits = decltype(get_enum_traits(T{}));
Run Code Online (Sandbox Code Playgroud)

诀窍是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); 
Run Code Online (Sandbox Code Playgroud)

一些演示表明它确实有效。

#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)
    {}
}
Run Code Online (Sandbox Code Playgroud)