Templates parte 1
De ccppbrasil.org
Tabela de conteúdo |
Templates Parte I
Thiago Rosso Adams - 19/03/06
Resolvi escrever um pouco sobre templates, pois apesar de toda biblioteca padrão usar este conceito, muitas pessoas ainda tem uma visão muito superficial sobre este assunto, e deixam de tirar todo o proveito desta maravilhosa característica do C++.
Eu costumo dizer que com templates você faz o compilador trabalhar para você.
Vou colocar um exemplo para servir de motivação e tentar introduzir a nomeclatura de templates.
Motivação
Para iniciar vou usar o exemplo de uma função swap. Esta função faz a troca de valores entre duas variáveis.
void swap(int &a, int &b)
{
int temp(a);
a = b;
b = temp;
}
Mas também preciso da mesma função para double, para string e talvez para outros tipos. Pensando na implementação eu descubro que seria a mesma. Será que o compilador não poderia nos dar uma ajuda ? - Sim e com templates ele pode.
Para isso declaramos uma função template.
Esta função foi chamada de “swap” e possui um parâmetro template chamado “T”.
template<class T>
void swap(T & a, T & b)
{
T temp(a);
a = b;
b = temp;
}
int i1 = 1;
int i2 = 2;
swap(i1, i2); // ok
double d1 = 1.0;
double d2 = 2.0;
swap(d1, d2); // ok
A função swap é instanciada para int e para double pois o compilador pode deduzir o tipo T através do argumento.
De forma similar os templates podem ser usados para declaração de classes.
Por exemplo:
template <class T>
class Array
{
T * m_pointer;
[ … ]
T & at(unsigned int index) const {
return m_pointer[index];
}
[ … ]
}
Neste exemplo a classe array precisa ser instanciada para o tipo T. Ela é chamada de uma classe template.
Array<int> array; // o tipo T precisa ser informado aqui
Este exemplo é encontrado em toda STL com o uso de containers. A vantagem é clara, você não precisa trabalhar de forma polimórfica com os tipos, pois o que você deseja realmente é um array de inteiros.
Até aqui espero que a motivação para o uso esteja clara, e vou lembrar que esta é apenas a “ponta do iceberg”.
Especialização
Uma versão do template para um tipo em especial é chamada especialização. Existem dois tipos de especialização especialização completa ou explícita e a especialização parcial.
Para toda especialização primeiramente é preciso um template primário com o caso geral.
Pegando o exemplo da função swap, que será nosso template primário e já foi definido.
Uma especialização para o tipo int seria:
Template<>
void swap(int & a, int & b)
{
cout << “quando usar int parece esta mensagem”;
int temp = a;
a = b;
b = temp;
}
Este exemplo é simples e talvez não pareça muito útil. Mas eu apenas resisti a tentação de não escrever uma especialização parcial neste momento.
- A especialização completa é usada para definir uma classe template para um número exato de argumentos.
Especialização Parcial
Vamos seguir adiante.
Especialização parcial é uma especilização em que você necessita de mais parâmetros para concluir a sua especialização.
Neste caso a lista de parâmetros não é vazia.
É possível criar uma especialização parcial para o caso de ponteiros por exemplo ou qualquer outro caso.
Voltando ao exemplo da função swap, ela será usada aqui para a especialização da o tipo Array.
Apenas para deixar clara a diferença, uma especialização completa para a classe Array poderia ser escrita assim:
template< >
void swap<Array<int> & a, Array<int> & b>
{
[…]
}
Não parece muito útil certo? Pois esta função funcionaria apenas para o caso de um Array<int>.
Então este é o caso em que a especialização partial é nescessária.
Template<class T>
void swap( Array<T> & a, Array<T> & b)
{
a.swap(b);
}
em que Array::swap poderia ser definida assim:
void Array<T>::swap(Array<T> & b)
{
T * tmp = m_pointer;
m_pointer = b.m_pPointer;
b.m_pointer = tmp;
}
Agora a função swap pode ser usada em qualquer Array e a especialização tornou a função muito mais eficiente e segura para o caso da classe Array, em que não será preciso fazer uma cópia.
- Especialização parcial é uma especilização em que você necessita mais parâmetros para concluir a sua especialização.
Ainda tem mais?
É possível escrever um livro inteiro só sobre templates. Um dos livros mais completos sobre o assunto é "C++ Templates: The Complete Guide" por David Vandevoorde e Nicolai M. Josuttis.
Existem mais conceitos importantes e outros detalhes sobre especialização que não foram expostos. Quando tiver tempo tentarei escrever outras partes nas quais faltaram comentários.
- Parâmetros default
- Embedded type information
- Traits
- SFINAE
- typename x class
- membros template
- templates de templates
- Policies
- algorítmos
- tratamento de exceções para templates.
Referências:
The C++ programming language, Bjarne Stroustrup
C++ Common Knowledge, Stephen C. Dewhurst
