Как лучше специализировать методы в шаблонном классе
Написал простой пример. Есть шаблонный класс Printer, у которого метод Print. Мне нужно при определенных типах данных специализировать метод Print добавляя к нему только "шапку" для определенного типа данных (включая класс). Я решил задачу таким образом:
template<class T>
class Printer
{
public:
void Print();
};
template<class T>
void Printer<T>::Print()
{
cout << "This is method print";
}
template<>
void Printer<int>::Print()
{
cout << "Header for int ";
cout << "This is method print";
}
template<>
void Printer<Cottage>::Print()
{
cout << "Header for cottage ";
cout << "This is method print";
}
Однако когда я создаю реальную программу я сталкиваюсь с тем, что мне нужно постоянно копировать все поля метода по умолчанию. Таким образом кода становится реально много, а ведь мне всего лишь нужно добавить немного текста. Есть ли другой способ решить задачу?
Ответы (3 шт):
Как вариант, можно добавить базовый класс:
template<class T>
class PrinterBase {
public:
void Print() {
cout << "This is method print";
}
};
template<class T>
class Printer: public PrinterBase<T> {
public:
void Print() {
PrinterBase::Print();
}
};
template<>
void Printer<int>::Print() {
cout << "Header for int ";
PrinterBase::Print();
}
Или просто перенести реализацию в отдельный метод:
template<class T>
class Printer: public PrinterBase<T> {
public:
void Print() {
PrinterBase::doPrint();
}
private:
void doPrint() {
cout << "This is method print";
}
};
template<>
void Printer<int>::Print() {
cout << "Header for int ";
doPrint();
}
Приведенный вами пример позволяет даже не определять специализации. Можно определить шаблон и еще одну функцию(если вам нужно), которая будет вызвана, если тип не тот и не другой:
void print(){
//добавить код
cout << " template parameter.\n";
}
template<class T>
void Printer<T>::Print()
{
cout << "Header for ";
if constexpr (std::is_same_v<T, int>)
cout << "int ";
else if constexpr (std::is_same_v<T, Cottage>)
cout << "cottage ";
else
print();
cout << "This is method print. ";
}
Из вопроса явно не видна необходимость именно в шаблонных классах, поэтому вполне можно обойтись и без них с помощью обычного наследования и виртуальных функций:
#include <iostream>
class Printer {
public:
void Print() { PrintHeader(); std::cout << "This is method print"; }
protected:
virtual void PrintHeader() = 0;
};
class PrinterInt : public Printer {
void PrintHeader() override { std::cout << "Header for int "; }
};
class PrinterCottage : public Printer {
void PrintHeader() override { std::cout << "Header for cottage "; }
};
int main() {
Printer* p = new PrinterCottage();
p->Print();
}
Видно, что в этом решении достаточно только реализовать один единственный метод печати заголовка в производном классе, минимизировав дублирование кода или его смешивание в кучу для несвязных типов.
Если всё же шаблон необходим, то можно легко сделать базовый класс таковым, но это усложнит хранение экземпляров разных классов, т.к. между ними уже не будет иерархии с единым корнем.