Пример шаблонной функции:
template <class T> void swap (T& a, T& b) { T t(a); a = b; b = t; }
По умолчанию шаблонные функции
считаются inline
(могут совпадать
в различных единицах трансляции).
Параметрами шаблонов могут быть
Пример — функция интегрирования:
double log (double x); template <class F> integrate (double a, double b, double eps, F s); integrate (1, 2, 1e-10, log);
(Здесь log
приводится к указателю на функцию.)
Пример с целочисленными параметрами — библиотека линейной алгебры, в которой операции определяются только для операндов одинаковой размерности (векторов, матриц):
template <size_t N> struct vector { ... }; template <size_t M, size_t N> struct matrix { ... }; template <size_t N> vector<N> operator+ (const vector<N>& a, const vector<N>& b) { for (size_t i=0; i!= N; i++) { ... } } template <size_t L, size_t M, size_t N> Matrix<L,N> operator* (const Matrix<L,M>& m1, const Matrix<M,N>& m2) { for (size_t i=0; i != L; i++) { for (size_t j=0; j != N; j++) { for (size_t k=0; k != M; k++) { ... } } } }
Пример шаблонного конструктора копирования:
template <class T> struct vector { template <class V> vector (vector<V> const&) { ... } };
Указатели можно было бы использовать, скажем, в гипотетическом классе, который имеет в качестве параметра ключ шифрования в виде массива:
template <int* key> ...
Здесь key
должен быть указателем на
переменную со внешней линковкой (глобальную в сильном
смысле).
Иногда возникает необходимость в переменных с
внутренней линковкой. Пусть имеется очень
сложный алгоритм (например, он что-нибудь перестраивает,
и в честь этого зовётся reorder
),
использующий много вспомогательных методов и имеющий
внутреннее состояние. В таком случае может оказаться
удобным определить класс прямо внутри функции, и там же
создать его экземпляр и что-то с ним сделать:
void reorder() { // Внутренняя линковка! struct Reorder { ... } Reorder x(...); }
Специализация — это переопределение шаблона для конкретного значения параметра.
Например, обычный шаблон
массива vector<T>
не хотелось бы
использовать в случае vector<bool>
, так
как булевы значения разумно упаковывать в целые
слова.
template <class T> struct vector { // обычный массив }; template <> struct vector <bool> { // компактный массив булевых значений };
То, что тут происходит (обратите внимание на синтаксис), и называется (полной) специализацией.
Тонкий момент — перегрузка задействуется до выбора специализации. Если что-то подходит лучше шаблонов, то оно и вызывается.
void f (float); template <class T> void f(T); template <> void f<double> (double); f (1.5); // вызов первой функции f ((double) 1.5); // вызов второй функции
Иногда нужно использовать частичную специализацию, такую как в следующем примере.
template <class T> struct vector { ... }; template <class V> struct vector<vector<V> > { ... };
Здесь после специализации остался не зафиксированный параметр — V. Без надобности частичную специализацию использовать не стоит.
С шаблонами бывает удобно
использовать typedef
, чтобы записывать
имена типов более коротко:
typedef vector<vector<int> > VVInt;
Важно, что typedef
вводит имя,
к которому потом можно обращаться:
template <class T> struct vector { typedef T value_type; };
Иногда возникают зависимые имена типов (не путать с
dependent types :-) — такие, которые вычисляются из
шаблонных параметров. Они могут не опознаваться
компилятором, поэтому бывает необходимо указывать
ключевое слово typename
:
template <class V> void f (V const& v) { typename V::value_type t = v[0]; v[0] = v[1]; v[1] = t; }
Следующий код вычисляет при помощи шаблонов N-е число Фибоначчи на стадии компиляции.
// Индуктивное определение: template <size_t N> struct fib { static const int value = fib<N-1>::value + fib<N-2>::value; }; // Базовые значения задаются при помощи специализации: template<> struct fib<0> { static const int value = 0; }; template<> struct fib<1> { static const int value = 1; };
В соответствии с правилами раскрытия шаблонов, мы даже знаем, что вычисление будет линейным.
Другие забавные примеры cм. в книге David Abrahams, Aleksey Gurtovoy, C++ Template Metaprogramming, AW, 2004.