Pular para o conteúdo principal

Por quê usar templates ?

Se você não está usando templates com C++, você está perdendo toda a diversão.

A linguagem C++, apesar de suportar orientação a objetos, diferentemente de Java, não te "obriga" a usá-la. Você poderá ter o melhor dos mundos, em termos dos paradigmas e idiomas. Um pouco de orientação a objetos aqui e programação genérica ali, tudo isto no mesmo código!

Vamos fazer uma implementação do seguinte código:

https://gist.github.com/thiagomg/9e977b4c088734a95769


Primeiro uma implementação tipicamente orientada a objetos pode ser:

https://gist.github.com/thiagomg/f8cfa473268ace1dde05

Vejam só que em uma única classe, para ser de propósito geral e suportar diversos tipos, foram implementados os métodos:
1: string_builder &add(int v)
2: string_builder &add(const std::string &v)
3: string_builder &add(const char *v)
4: string_builder &add(double v)
5: string_builder &add(bool v)
6: string_builder &add(unsigned int v)
7: string_builder &add(float v)
8: string_builder &add(long long v)
9: string_builder &add(unsigned long long v)
//Faltando ainda short/char/etc

Para uma simples concatenação, temos estas várias implementações, todas quase iguais.

Agora vamos ao template.

O que ele faz ?

O código com template só existe quando é instanciado, ou seja, ele é completamente genérico.
Vamos fazer essa implementação de forma "templatizada":

https://gist.github.com/thiagomg/9ed2f69d01a186923ab8

Bem mais sucinto, não acha ?
Quando o add for chamado, o T será substituído pelo tipo concreto. No caso da chamada s.add(1), será gerado:

https://gist.github.com/thiagomg/c8ca78850db01d88e97e

No entanto, pode surgir a seguinte pergunta: E se eu quiser fazer um tratamento para algum caso específico ? É ai que o template fica ainda mais interessante.

O template tem uma característica muito interessante chamada especialização. Neste caso, é definido o caso genérico com T, e também todos os casos específicos, onde um determinado tipo terá seu tratamento diferenciado. Por exemplo, é possível adicionar um bool, e ao invés dele virar 0 ou 1, ele seja projetado com Y ou N, para true e false respectivamente.

A especialização ficaria assim:
https://gist.github.com/thiagomg/3141aaba344aaf8c029c

E vendo a forma genérica, podemos pensar: Como eu faço para ele tratar o meu próprio tipo ? Se fosse orientado a objetos, seria necessário alterar a classe ou criar uma classe que herdasse dela e usá-la. Isso seria algo do tipo:

https://gist.github.com/thiagomg/82c27701ac7e1861e667

Porém, ao invés de fazer isso, podemos simplesmente usar uma especialização de template.

https://gist.github.com/thiagomg/1929547c54a505e83902

Desta forma o código, além de elegante e sucinto, ficará bem flexível, rápido e divertido.
Parece até que está sendo escrito um código em uma linguagem como Python onde o tipo é sempre inferido.

Fontes:
https://github.com/SimplyCpp/examples/blob/master/templ_oo.cpp
https://github.com/SimplyCpp/examples/blob/master/templ.cpp

Comentários

  1. […] “Desde 2012, o C++ está voltando ao mainstream com força total. Há muitos desenvolvedores que vieram do C e fazem C com classes ao invés de usar o que há de mais poderoso no C++, o meta-programming. Neste post é feita uma introdução aos templates e uma mostra de caso onde ele é muito mais fácil do que orientação a objetos.” [referência: simplycpp.com] […]

    ResponderExcluir

Postar um comentário

Postagens mais visitadas deste blog

Mestre Iota

Iota é a nona letra do alfabeto grego, ela é equivalente à letra i do nosso alfabeto. Por convenção ou hábito, utilizamos a letra i na programação para indicar algum tipo de incrementador, como por exemplo, em um for-loop . https://gist.github.com/fabiogaluppo/a23894ae743f7dd29274 Curiosamente, iota , como identificador, também é utilizado na programação para indicar uma sequência finita e consecutiva de números inteiros, como por exemplo, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]. Inclusive, originalmente na STL existia a função iota , inspirada pela linguagem de programação APL , você pode conferir neste link: http://www.sgi.com/tech/stl/iota.html

Valores Aleatórios Simplificados

A partir do C++ 11, foi introduzido o header <random>  com diversos facilitadores para suporte de geração de números aleatórios. A produção destes números é feita através da combinação de duas categorias de objetos: os geradores e os distribuidores. Os geradores, são responsáveis pela geração dos números, e os distribuidores são responsáveis pela transformação dos números gerados em algum tipo de distribuição de probabilidade.  Como por exemplo, uma distribuição normal (aquela da Gaussiana) ou uma distribuição de Pareto (aquela do 80-20). As opções não faltam, como você pode ver nas referências, por exemplo:   http://www.cplusplus.com/reference/random/ ou  http://en.cppreference.com/w/cpp/header/random .

Policy-based design: log writer

Policy-based design Vamos neste artigo dar mais uma pincelada no Policy-based design . Vamos fazer como exemplo uma classe de log. Como este é só um exemplo, não vamos considerar múltiplos parâmetros no log, mas somente uma string, assim não fugiremos do assunto. Uma das coisas mais importantes neste tipo de design é o desacoplamento. Ele é uma excelente alternativa ao uso de interfaces por duas razões: Não gera chamadas virtuais (ou um nível de indireção em tempo de execução) Duck typing ( https://pt.wikipedia.org/wiki/Duck_typing ) Eu gosto bastante desse tipo de design, já usado aqui: http://simplycpp.com/2016/02/05/leitura-de-configuracao-em-c/