Visão geral de modelos
Os modelos, chamados às vezes de tipos com parâmetros, são mecanismos para gerar funções e classes com base em parâmetros de tipo. Usando modelos, você pode criar uma única classe ou função que funcione em dados de diversos tipos, em vez de criar uma classe diferente para cada tipo.
Comentários
Por exemplo, para criar uma função typesafe que retorne o valor mínimo de dois parâmetros sem usar modelos, você teria que escrever um conjunto de funções sobrecarregadas como este:
// 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;
}
Usando modelos, você pode reduzir essa duplicação a um único modelo de função:
// what_are_templates2.cpp
// compile with: /c
template <class T> T min( T a, T b ) {
return ( a < b ) ? a : b;
}
Os modelos podem reduzir significativamente o tamanho do código-fonte e aumentar a flexibilidade do código sem reduzir a segurança de tipo.
Há dois tipos principais de modelo: modelos de função e modelos da classe. No exemplo anterior, min é um modelo de função. Um modelo de classe é uma classe com um parâmetro, como:
// 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);
}
Os modelos são declarados e definidos de maneira parecida como outras funções e classes, com algumas diferenças principais. Uma declaração modelo não define totalmente uma função ou classe; ela apenas define um esqueleto sintático para uma classe ou função. Uma classe ou uma função real é criada a partir de um modelo por um processo chamado instanciação. As classes ou as funções individuais criadas são chamadas de instanciadas. Por exemplo, um modelo de classe:
template <class T> struct A { . . . };
pode ser usado para instanciar classes para A<int>, A<char>, A<int*>, A<MyClass*>, e assim por diante.
A instanciação das classes ou funções pode ser feita explicitamente ou implicitamente. A instanciação explícita é uma maneira de chamar dentro do código as versões do modelo que devem ser geradas. A instanciação implícita permite que os modelos sejam instanciados conforme o necessário no ponto onde são usados pela primeira vez.
Os modelos também podem ser parametrizadas por um parâmetro de valor. Nesse caso, o parâmetro de modelo é declarado como o parâmetro de uma função. Os tipos de ponto flutuante e de classe não são permitidos como parâmetros de valor.
// 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;
}
Um problema comum com modelos é que eles podem ser uma solução do tipo "tamanho único", o que significa que o mesmo código se aplica a todos os tipos. Se você precisar personalizar o comportamento do modelo para um tipo específico, pode usar a especialização. Usando a especialização explícita, um modelo pode ser especializado para um tipo real em particular, não um tipo genérico. Um modelo de classe também pode ser parcialmente especializado, o que é útil se você tiver um modelo com vários parâmetros de tipo e quiser apenas personalizar o comportamento em relação a alguns parâmetros, mas não a todos. Uma especialização parcial ainda é genérica e precisa de argumentos reais do modelo para gerar uma classe instanciada real.