Подтвердить что ты не робот

Почему шаблон <T>, но не шаблон <> должен быть определен за пределами блока пространства имен?

Вот код, который не компилируется.

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;
}

Ошибка: "специализация" template int ns:: foo:: bar (T *) в разных пространствах имен [-fpermissive] из определения "template int ns:: foo:: bar (T *)"

Вот версия, которая компилируется:

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;
    }
}

Почему второе определение должно быть в блоке namespace ns {}, когда первый из них довольно удачно определен с помощью квалифицированного имени? Это просто недосмотр в дизайне языка или есть причина для этого?

4b9b3361

Ответ 1

Проблема здесь не в определении, а в декларации. Вы не можете вводить объявление в пространство имен из другого пространства имен, поэтому специализация должна быть объявлена ​​в соответствующем пространстве имен, прежде чем она может быть определена в любом охватывающем пространстве имен.

Определение базового шаблона может быть сделано во внешнем пространстве имен, поскольку оно уже было объявлено, поэтому код во внешнем пространстве имен предоставляет определение, но не вводит никакое объявление в пространство имен.

Try:

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;
}