Templates parte 2
De ccppbrasil.org
Tabela de conteúdo |
Templates parte II
Thiago Adams 27/3/06
No artigo anterior mostrei a nomeclatura usada em templates e o conceito de especializacao. Nesta segunda parte vou escrever sobre o conceito de Embedded Type Information e Traits/Police.
Estes conceitos não são uma característica da linguagem (como é o caso da especialização) mas são nomes dados para algumas técnicas usadas com templates.
Além de esclarecer algumas dúvidas vou tentar conectar os conceitos com a STL.
Embedded Type Information
Embedded Type Information é a capacidade de um tipo armazenar informações relevantes a si próprio.
Esta capacidade está intimamente ligada aos templates pois podem fornecer a eles a informação de que necessitam para sua instância. Esta informação é colocada em forma de typedefs.
Os containers da STL são exemplos de classes com embedded type information.
Pegando o vector como exemplo, encontramos nele os seguintes typedefs:
allocator_type , const_iterator, const_pointer, const_reference, const_reverse_iterator, difference_type, iterator, pointer, reference, reverse_iterator, size_type, value_type.
Este typedefs informam o tipo de iterator, o tipo do allocator, o tipo de dado usado etc, e são utilizados em algorítmos genéricos.
Por exemplo posso perguntar para o container “T”:
Qual é o seu iterator? Qual o tipo de allocator você utiliza?
Uma função template usando a informação do container “T”
template<class T> void printAll(T & container)
{
T::iterator it = container.begin(); //<--
For ( ;it != container.end(); ++it)
cout << *it;
}
- Percebam que caso a informação do tipo do iterator não estivesse declarada no container eu precisaria de um parâmentro extra na minha função template.
Traits
Algumas vezes a informação contida em um tipo não é suficiente para a implementação de um template. Outras vezes, o tipo não possui e não pode conter nenhuma informação extra, como é o caso dos tipos básicos int, double, etc.
Os Traits podem ser usados nestes casos.
Traits, é uma pequena classe que traz informações sobre um tipo e/ou informações de como lidar com ele.
Podem ser usados em outras classes ou em algorítmos.
Exemplo: Vamos supor que eu queria percorrer um container de ponteiros e deletar todos os items:
template<class T> void DeleteAllItems(T & container)
{
T::iterator it = container.begin();
for ( ;it != container.end(); ++it)
{
delete *it;
}
container.clear();
}
Esta função template funciona perfeitamente para um ponteiro convencional. No entanto eu posso ter o mesmo algorítmo para deletar uma lista de objetos COM. (No COM é usado um método Release da interface IUnknown ao invés do operator delete)
Neste caso preciso tratar os diferentes tipos de ponteiros. Esta informação pode ser colocada externamente com a utilização de Traits.
Um Traits que contenha informação de como deletar o ponteiro pode ser definido assim:
// caso genérico
template<class T> void DeleteItemTraits(T p) {
delete p;
}
// especializando para o caso do IUnknown
template<> void DeleteItemTraits(IUnknown *p) {
p->Release(); // caso de um ponteiro COM
}
E o algorítmo genérico pode ser escrito:
template<class T> void DeleteAllItems(T & container)
{
T::iterator it = container.begin();
for ( ;it != container.end(); ++it)
{
DeleteItemTraits<T::value_type>(*it); //<--
}
container.clear();
}
O termo Police também é usado para Traits, para dar a noção de ações sobre o tipo, e não apenas informações. Poderia chamar minha função de DeletePolice por exemplo. A STL possui vários exemplos de Traits. Um destes é a implementação da std::numeric_limits. A numeric_limits possui a função max() que retorna o máximo valor que pode ser contido no tipo.
Exemplo:
cout << "The maximum value for type int is: "
<< numeric_limits<int>::max( ) //*
<< endl;
Neste caso não era possivel colocar a informação do valor de max dentro do tipo int. Por isso o conceito de traits foi usado. Traits também são usados na STL em classes como a basic_string que precisa de um Traits para tratar o caso do tipo de caractere usado (char ou wchar_t).
- Não foi comentado no artigo I, mas quando o tipo do template não pode ser deduzido pelo argumento o programador explicitamente informa o tipo com a syntaxe nomefuncao<tipo>, como é o caso da numeric_limits.
Referências
The C++ programming language, Bjarne Stroustrup
C++ Common Knowledge, Stephen C. Dewhurst
