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:
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
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
[…] “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