Generics em C++: para que servem e como usar
Olá, amigo! Se você está começando a aprender C++ e já se deparou com o conceito de Generics (ou templates), este artigo é para você. Muitos iniciantes têm medo de templates, achando que são algo complexo e mágico. Na verdade, é muito mais simples. Vamos entender o que são, para que servem e como aplicá-los na prática.
O que são Generics (templates) em C++?
Imagine que você precisa escrever uma função que soma dois números. Você escreve uma função para int, outra para double, outra para float… Concordo, é cansativo e viola o princípio DRY (Don't Repeat Yourself).
É aqui que os templates entram em ação. É um mecanismo que permite escrever código genérico que funciona com qualquer tipo de dado. Em C++, isso é o análogo do que em outras linguagens chamam de Generics (por exemplo, em Java ou C#).
Um template não é uma função ou classe específica, mas um "projeto" ou "receita". O compilador, ao ver que você usa um template com o tipo int, cria uma versão do código para int. Se você o usa com double, o compilador cria uma versão para double. Isso é chamado de instanciação de template.
Para que servem os templates? Três razões principais
1. Reutilização de código
Em vez de escrever 10 funções para diferentes tipos numéricos, você escreve uma função universal. Isso economiza tempo, reduz o número de erros e torna o código mais legível.
2. Segurança de tipos
Ao contrário de macros (#define) ou do uso de void*, os templates são verificados pelo compilador. Se você tentar passar um tipo inadequado para o template, o compilador emitirá um erro em tempo de compilação, não durante a execução do programa.
3. Desempenho
Os templates não adicionam sobrecarga em tempo de execução. O compilador cria código otimizado para cada tipo específico, e esse código funciona tão rápido quanto se você o tivesse escrito manualmente.
Como usar templates: sintaxe e exemplos
Vamos considerar dois tipos principais de templates: templates de funções e templates de classes.
Templates de funções
O exemplo mais simples é uma função que encontra o máximo entre dois valores.
#include <iostream>#include <string>
// Declaração do template de funçãotemplate <typename T>T max_value(T a, T b) { return (a > b) ? a : b;}
int main() { // Funciona com int std::cout << max_value(10, 20) << std::endl; // Saída: 20 // Funciona com double std::cout << max_value(3.14, 2.71) << std::endl; // Saída: 3.14 // Funciona com strings std::cout << max_value(std::string("apple"), std::string("banana")) << std::endl; // Saída: banana return 0;}A palavra-chave template diz ao compilador: "Atenção, a seguir vem um template". <typename T> é a lista de parâmetros do template. T é um nome de tipo temporário que será substituído pelo tipo real na chamada da função. Em vez de typename, você pode usar class — não há diferença.
Importante: O compilador deduz automaticamente qual tipo você quer usar com base nos argumentos passados. Isso é chamado de dedução de argumentos de template. Mas você pode especificar o tipo explicitamente:
std::cout << max_value<double>(10, 20.5) << std::endl; // Especificamos explicitamente o tipo doubleTemplates de classes
Os templates de classes permitem criar contêineres de dados universais. Um exemplo clássico é um análogo simples de std::pair.
#include <iostream>#include <string>
// Template