在另一个命名空间中定义符号

Luc*_*lle 3 c++ templates namespaces

这是我的问题:在标题中我定义了一个结构模板type_to_string,其目的是定义一个对应于给定类型参数的字符串:

namespace foo {

    template <typename T>
    struct type_to_string
    {
        static const char * value;
    };
}

template <typename T>
const char * foo::type_to_string<T>::value = "???";
Run Code Online (Sandbox Code Playgroud)

我还定义了字符串的默认值.

现在,我想使用宏来定义新类型:

#define CREATE_ID(name)                               \
struct name;                                          \
                                                      \
template<>                                            \
const char * foo::type_to_string<name>::value = #name;
Run Code Online (Sandbox Code Playgroud)

问题是我希望宏可以在命名空间中使用,如:

namespace bar
{
    CREATE_ID(baz)
}
Run Code Online (Sandbox Code Playgroud)

这是不可能的,因为type_to_string<T>::value必须在封闭的命名空间中定义foo.

这是我得到的编译错误:

[COMEAU 4.3.10.1] error: member "foo::type_to_string<T>::value [with T=bar::baz]"
cannot be specialized in the current scope

[VISUAL C++ 2008] error C2888: 'const char *foo::type_to_string<T>::value' :
symbol cannot be defined within namespace 'bar'
     with
     [
         T=bar::baz
     ]
Run Code Online (Sandbox Code Playgroud)

奇怪的是,GCC 4.3.5(MinGW版本)不会产生任何错误.

有没有人知道这方面的解决方法,也许通过使用一些我不知道的查找规则(即type_to_string在宏中声明,以便每个命名空间都有自己的版本,或类似的东西)?

Kir*_*sky 9

根据C++标准14.7.3/2:

应在模板所属的名称空间中声明显式特化,或者对于成员模板,在封闭类或封闭类模板所属的名称空间中声明.应该在类模板所属的名称空间中声明类模板的成员函数,成员类或静态数据成员的显式特化.这样的声明也可以是一个定义.如果声明不是定义,则可以在稍后在声明显式特化的名称空间中定义特化,或者在包含声明显式特化的名称空间中定义特化.

您可以编写如下内容:

#define DECL_ID(name) \
struct name;                                          

#define CREATE_ID(name) \
template<>              \
const char * foo::type_to_string<name>::value = #name;

namespace bar { namespace bar2 {
    DECL_ID(baz)
} }
CREATE_ID(bar::bar2::baz)
Run Code Online (Sandbox Code Playgroud)

要么

#define CREATE_ID(ns, name)     \
namespace ns { struct name; }   \
                                \
template<>                      \
const char * foo::type_to_string<ns::name>::value = #name;

CREATE_ID(bar, baz)
Run Code Online (Sandbox Code Playgroud)

第三种选择是前两种的叠加.它允许具有不合格的名称value(如果需要):

#define DECL_ID(name) \
struct name;                                          

#define CREATE_ID(ns, name) \
template<>              \
const char * foo::type_to_string<ns::name>::value = #name;

namespace bar { namespace bar2 {
    DECL_ID(baz)
} }
CREATE_ID(bar::bar2, baz)
Run Code Online (Sandbox Code Playgroud)