Частичная специализация двойного шаблона не удалась - PullRequest
7 голосов
/ 09 февраля 2011

Есть шаблон класса List.

template <typename Point>
class List
{


    public:
          template <const unsigned short N>
          void load ( const char *file);
          ...
};

template <typename Point>
template <const unsigned short N>
void List <Point>::load ( const char *file)
}

Как специализировать метод загрузки для N = 2? Этот код недействителен ...

template <typename Point>
void List <Point> <2>::load ( const char *file)
{
}

И этот код тоже не работает.

template <typename Point>
void List <Point> ::load <2> ( const char *file )
{ 
}

Error 3 error C2768: 'List<Point>::load' : illegal use of explicit template arguments 66. 
Error 5 error C2244: 'List<Point>::load' : unable to match function definition to an existing declaration 66

Компилятор g ++:

template <typename Point>
template <>
void List <Point> ::load <2> ( const char *file )
{
}

error: explicit specialization in non-namespace scope `class List<>'
error: enclosing class templates are not explicitly specialized
error: default arguments are only permitted for function parameters
error: `load' is not a function template
error: invalid function declaration

Ответы [ 3 ]

8 голосов
/ 10 февраля 2011

Оказывается, что в спецификации C ++ есть положение, которое явно запрещает специализировать класс шаблона или функцию, вложенную в класс шаблона, если вы также явно не специализируете внешний шаблон.Visual Studio не применяет это правило, поэтому возникает путаница с предыдущим примером, но g ++ определенно это делает.

Если вы хотите специализировать шаблон, ваши варианты будут либо специализироваться на внешнем шаблоне, либо каким-то образомподделать поведение специализации, отправив метод одной из двух разных реализаций на основе параметра шаблона.Я знаю, что ни один из них не очень приятен, но, к сожалению, в некоторых углах шаблонов язык выглядит странно.: - (

Один из способов, которым вы можете эмулировать поведение явной специализации, - это использовать метод, называемый диспетчеризация тегов . Идея состоит в том, что мы создадим очень простую структуру, которая выглядиткак это:

template <unsigned short N> struct Box {};

Этот тип полностью пустой. Он не предназначен для непосредственного использования, а просто является способом встраивания целого числа в систему типов. В частности, Box<3> не являетсятот же тип, что и Box<4> и т. д.

Затем в своем классе списка определите две функции, которые выглядят следующим образом, предпочтительно помеченные как private:

template <unsigned short N>
    void doLoad(const char* file, Box<N>);
void doLoad(const char* file, Box<2>);

Эти две функции являются перегрузками одногодругой, отличающийся только их последним параметром, который является либо Box<N> в случае шаблона, либо Box<2> в случае без шаблона. Обратите внимание, что параметры не имеют имен. Это произвольное решение, но так какмы не планируем на самом деле читать параметры, они нам не нужны. Интуиция за этими функциями заключается в том, что эта первая функция будет универсальной реализациейИон, который будет работать для любого N, кроме 2. Вторая версия будет содержать реализацию загрузки для случая, когда N == 2.

Наконец, реализуем load следующим образом:

template <typename Point>
    template <unsigned short N>
void List<Point>::load(const char* file) {
    doLoad(file, Box<N>());
}

Как это работает?Эта функция принимает параметр, а затем вызывает doLoad, перенаправляя этот параметр в качестве первого аргумента и передавая временный Box<N> в качестве второго аргумента.Если N не два, то это вызов шаблонной версии doLoad, которая является универсальным обработчиком.Если, с другой стороны, N равно двум, то это вызовет не шаблонную версию doLoad, потому что не шаблонные функции имеют приоритет над шаблонными функциями во время разрешения перегрузки.

Короче говоря,реализация load просто становится батутом, чтобы направить вас к правильному из двух реализаций.Затем вы можете поместить логику в соответствующую функцию doLoad, чтобы получить желаемое поведение.

Надеюсь, это поможет!

1 голос
/ 10 февраля 2011

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

Мне также интересно, что может означать значение N, поскольку оно не используется в параметре функции?

1 голос
/ 09 февраля 2011

Редактировать : Итак, я немного переписал ваш класс с встроенными определениями функций, и это определенно работает:

template <typename Point>
class List
{
public:
    template <const unsigned short N>
    void load( const char *file){
    }

    template<>
    void load<2>(const char* file){
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...