Если я хочу специализировать только один метод в шаблоне, как мне это сделать? - PullRequest
27 голосов
/ 17 февраля 2012

Скажем, у меня есть шаблонный класс, такой как

template <typename T> struct Node
{
    // general method split
    void split()
    {
        // ... actual code here (not empty)
    }
};

Нужно специализировать это в случае с классом Triangle .. что-то вроде

template <>
struct Node <Triangle*>
{
    // specialise the split method
    void split() {}
} ;

но я не хочу переписать весь шаблон заново! Единственное, что нужно изменить - это метод split(), не более того.

Ответы [ 4 ]

31 голосов
/ 17 февраля 2012

Вы можете предоставить специализацию только для этой функции вне объявления класса.

template <typename T> struct Node
{
    // general method split
    void split()
    {
        // implementation here or somewhere else in header
    }
};

// прототип функции, объявленной в cpp void splitIntNode (Node & node);

template <>
void Node<int>::split()
{
     splitIntNode( this ); // which can be implemented
}

int main(int argc, char* argv[])
{
   Node <char> x;
   x.split(); //will call original method
   Node <int> k;
   k.split(); //will call the method for the int version
}

Если splitIntNode нужен доступ к закрытым членам, вы можете просто передать этих членов в функцию, а не весь узел.

6 голосов
/ 17 февраля 2012

Просто определите некоторые

template<>
void Node<Triangle*>::split()
{
}

после основного шаблона, но до того, как вы впервые его создадите.

5 голосов
/ 17 февраля 2012

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

Например, это работает:

template<typename T, typename U>
struct Node
{
    void function() { cout << "Non-specialized version" << endl; }
};

template<>
void Node<int, char>::function() { cout << "Specialized version" << endl; }

Частично специализированная версия, хотя не будет работать:

template<typename T, typename U>
struct Node
{
    void function() { cout << "Non-specialized version" << endl; }
};

template<typename U>
void Node<int, U>::function() { cout << "Specialized version" << endl; }

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

2 голосов
/ 17 февраля 2012

Неудобный метод, который я обычно использую: Объявить «базовую» реализацию шаблона.Затем объявите реализацию шаблона, реализация по умолчанию просто унаследует «базовую».Настройка будет наследовать «базовые», а также переопределять определенные методы.Например:

template <typename T> struct NodeBase
{
    // methods
};

template <typename T> struct Node
    :public NodeBase<T>
{
    // nothing is changed
};

template <> struct Node<SpecificType>
    :public NodeBase<SpecificType>
{
    // re-define methods you want
};

Обратите внимание, что «переопределение метода» не имеет ничего общего с виртуальными функциями и т. Д. Это просто объявление функции с тем же именем и параметрами, что и в базе - компилятор автоматическииспользуйте это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...