C++ 声明是否可以转义其封闭的命名空间?

C++ 声明是否可以转义其封闭的命名空间?,c++,namespaces,C++,Namespaces,我正在尝试编写一个宏来帮助构建一个带有各种辅助函数的enum类,例如用于转换为字符串。在某种集合中提供对枚举的所有值的访问是很自然的: DEFINE_ENUM(Foo, Value1, Value2); for (Foo v : enum_traits<Foo>::all_values) { // ... } 但是,如果扩展定义_ENUM(Foo,Value1,Value2)发生在命名空间内部,则它似乎不可能从该命名空间外部专门化模板: template<typen

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

DEFINE_ENUM(Foo, Value1, Value2);

for (Foo v : enum_traits<Foo>::all_values) {
    // ...
}
但是,如果扩展
定义_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> { /* ... */ };
}
template struct enum_traits{};
名称空间foo{
//假设在此处调用DEFINE_ENUM:
枚举类Foo{Value1,Value2};
//错误:“enum\u traits”的类模板专门化
//必须在全局范围内发生
模板结构::枚举特征{/*…*/};
}

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

嗯,我无法直接帮助解决此模板专门化问题,我怀疑这是不可能的

但是,你可以通过以下方式实现你的真正目标:

看看窍门:

// globally:
template<typename T> 
using enum_traits = decltype(get_enum_traits(T{}));
有些人认为它真的有效

#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)
    {}
}
#包括
//全球:
模板
使用enum_traits=decltype(get_enum_traits(T{}));
//在宏内部:
#定义枚举(名称,…)\
/*定义“枚举类名”…*/\
枚举类名{{uuu VA_ARGS}\
结构名称###(u类型){\
静态constexpr std::数组值{{Name{}}\
}; \
名称###类型(特征获取)枚举(名称)//不需要执行
名称空间foo{
定义_ENUM(Foo,Value1,Value2);
}
int main(){
用于(自动e:enum_traits::value)
{}
}

您可以通过在名称空间中定义,比如说,
struct Name###Traits
来避免本地类,并让
get_enum_Traits(Name)
只需返回它即可。@aschepler这是真的。可能是更好的解决方案。当您在for循环@Drew中实际使用
e
时,这似乎会导致链接器错误。这是因为您使用C++11,而constexpr变量在默认情况下不像在C++17中那样是内联的。但这个问题与OP问题无关。
// 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); 
#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)
    {}
}