为什么可以在命名空间块之外定义模板<T>而不是模板<>?

spr*_*aff 20 c++ templates

这是一些不编译的代码.

namespace ns
{
    class foo
    {
        template <typename T> int bar (T *);
    };
}

template <typename T>
int ns :: foo :: bar (T*) // this is OK
{
    return 0;
}

template <>
int ns :: foo :: bar <int> (int *) // this is an error
{
    return 1;
}
Run Code Online (Sandbox Code Playgroud)

错误是:"在'template int ns :: foo :: bar(T*)'的定义中,'template int ns :: foo :: bar(T*)'在不同命名空间[-fpermissive]中的特化"

这是一个编译的版本:

namespace ns
{
    class foo
    {
        template <typename T> int bar (T *);
    };
}

template <typename T>
int ns :: foo :: bar (T*)
{
    return 0;
}

namespace ns
{
    template <>
    int foo :: bar <int> (int *)
    {
        return 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么第二个定义必须在一个namespace ns {}块中,当第一个定义非常愉快地用限定名称定义时?它只是对语言设计的疏忽还是有理由这样做?

Dav*_*eas 14

这里的问题不是定义,而是声明.您不能从不同的命名空间中在命名空间中注入声明,因此必须先在相应的命名空间中声明特化,然后才能在任何封闭的命名空间中定义它.

基本模板的定义可以在外部名称空间中完成,因为它已经被声明,因此外部名称空间中的代码提供了一个定义但不向命名空间中注入任何声明.

尝试:

namespace ns {
    class foo
    {
        template <typename T> int bar (T *);
    };
    template <>
    int foo::bar<int>(int*); // declaration
}
template <typename T>
int ns :: foo :: bar (T*) {
    return 0;
}
template <>
int ns :: foo :: bar <int> (int *) {
    return 1;
}
Run Code Online (Sandbox Code Playgroud)