Обзор шаблонов
Шаблоны, которые иногда называются параметризованными типами, являются механизмами создания функций и классов на основе параметров типов. С помощью шаблонов можно создать отдельный класс или функцию, которая будет работать с данными множества типов, вместо того, чтобы создавать отдельный класс для каждого типа.
Примечания
Например, чтобы создать типобезопасную функцию, возвращающую как минимум два параметра, без использования шаблонов, необходимо написать набор перегруженных функций следующим образом.
// what_are_templates1.cpp
// compile with: /c
// min for ints
int min( int a, int b ) {
return ( a < b ) ? a : b;
}
// min for longs
long min( long a, long b ) {
return ( a < b ) ? a : b;
}
// min for chars
char min( char a, char b ) {
return ( a < b ) ? a : b;
}
С помощью шаблонов это дублирование можно сократить до одного шаблона функции.
// what_are_templates2.cpp
// compile with: /c
template <class T> T min( T a, T b ) {
return ( a < b ) ? a : b;
}
Шаблоны могут значительно сократить размер исходного кода и повысить гибкость кода, не снижая безопасность типов.
Существует два основных типа шаблонов: шаблоны функций и шаблоны классов. В предыдущем примере min — это шаблон функции. Шаблон класса — это класс с параметром (см. пример ниже).
// what_are_templates3.cpp
template <class T> class A {
T m_t;
public:
A(T t): m_t(t) {}
void f(T t);
};
int main() {
A<int> a(10);
}
Шаблоны объявляются и определяются подобно другим функциям и классам с некоторыми основными отличиями. Объявление шаблона не полностью определяет функцию или класс; определяется только синтаксическая структура класса или функции. Фактический класс или функция создаются с помощью шаблона в ходе процесса, называемого созданием экземпляра. Отдельные создаваемые классы или функции называются экземплярами. Например, шаблон класса
template <class T> struct A { . . . };
можно использовать для создания классов для A<int>, A<char>, A<int*>, A<MyClass*> и т. д.
Создавать экземпляры классов или функций можно явно или неявно. При явном создании экземпляра в коде вызываются версии шаблона для создания. При неявном создании экземпляра можно создавать экземпляры шаблонов по мере необходимости в месте их первоначального использования.
Кроме того, шаблоны можно параметризировать с помощью параметра значения, при этом параметр шаблона объявляется как параметр функции. Типы с плавающей запятой и типы классов не могут быть параметрами значений.
// what_are_templates4.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
template <int i> class A {
int array[i];
public:
A() { memset(array, 0, i*sizeof(int)); }
};
int main() {
A<10> a;
}
Общая проблема с шаблонами заключается в том, что они могут быть универсальным решением, то есть один и тот же код применяется ко всем типам. Если необходимо настроить поведение шаблона для определенного типа, можно использовать специализацию. Использование явной специализации шаблона можно настроить для определенного реального, а не универсального типа. Также можно частично настроить шаблон класса, что полезно при наличии шаблона с несколькими параметрами типов, когда требуется настроить поведение в соответствии с некоторыми, но не всеми параметрами. Частичная специализация по-прежнему является универсальной, и для создания фактического экземпляра класса требуются реальные аргументы шаблона.