Templates de Funções
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy. Lição 64 de 104.
Imagine escrever uma função para encontrar o maior de dois inteiros e, depois, perceber que você precisa da mesma lógica para números de ponto flutuante e, novamente, para strings. Sem templates, você escreveria funções quase idênticas para cada tipo. Os templates de função resolvem isso, permitindo escrever a lógica uma única vez e fazer com que o compilador gere automaticamente versões específicas para cada tipo.
Um modelo de função usa a palavra-chave template seguida por parâmetros de modelo entre colchetes angulares:
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}
int main() {
std::cout << maximum(5, 3) << std::endl; // Usa a versão int
std::cout << maximum(3.14, 2.71) << std::endl; // Usa a versão double
std::cout << maximum('a', 'z') << std::endl; // Usa a versão char
}O compilador examina cada chamada e gera uma função concreta para aquele tipo específico. Esse processo é chamado de instanciação de template. Você também pode especificar explicitamente o tipo quando necessário:
std::cout << maximum<double>(5, 3.14) << std::endl; // Força a versão doubleOs templates podem ter vários parâmetros de tipo, permitindo designs ainda mais flexíveis:
template <typename T, typename U>
void printPair(T first, U second) {
std::cout << first << ", " << second << std::endl;
}
printPair(42, "hello"); // T=int, U=const char*
printPair(3.14, 100); // T=double, U=intOs templates de função fornecem polimorfismo em tempo de compilação — o tipo é determinado quando o código é compilado, não em tempo de execução. Isso significa nenhuma sobrecarga em tempo de execução em comparação com funções virtuais, tornando os templates ideais para código genérico crítico para o desempenho.
Desafio
FácilVamos criar um kit de ferramentas utilitárias usando templates de função para criar operações reutilizáveis que funcionem com qualquer tipo compatível. Você organizará suas funções genéricas em um arquivo de cabeçalho e demonstrará sua flexibilidade no programa principal.
Você criará dois arquivos:
MathUtils.h: defina uma coleção de templates de função que realizam operações comuns:minimum: uma função template que recebe dois valores do mesmo tipo e retorna o menor deles.clamp: uma função template que recebe três parâmetros: um valor, um limite inferior e um limite superior. Ela retorna o valor restrito aos limites (retorna o limite inferior se o valor for menor que o limite inferior, o limite superior se o valor for maior que o limite superior; caso contrário, retorna o próprio valor).swapValues: uma função template que recebe duas referências do mesmo tipo e troca seus valores.main.cpp: leia seis entradas (cada uma em uma linha separada):- Primeiro inteiro
- Segundo inteiro
- Um valor double para limitar
- Limite inferior (double)
- Limite superior (double)
- Um caractere
Demonstre seus templates:
- Encontrando o menor dos dois inteiros e imprimindo:
Min of <a> and <b>: <result> - Encontrando o menor entre o caractere
'm'e o caractere informado, imprimindo:Min of m and <char>: <result> - Limitando o valor double e imprimindo:
Clamp <value> to [<low>, <high>]: <result> - Limitando o primeiro inteiro ao intervalo [0, 100] e imprimindo:
Clamp <value> to [0, 100]: <result> - Trocando os dois inteiros e imprimindo:
After swapValues: <a>, <b>
Por exemplo, com as entradas 25, 10, 3.7, 1.0, 5.0 e z:
Min of 25 and 10: 10
Min of m and z: m
Clamp 3.7 to [1, 5]: 3.7
Clamp 25 to [0, 100]: 25
After swapValues: 10, 25Observe como cada função template funciona perfeitamente com inteiros, doubles e caracteres: o compilador gera a versão apropriada para cada tipo usado. Sua função swapValues deve modificar as variáveis originais por meio de referências, demonstrando que os templates funcionam com parâmetros de referência assim como as funções comuns.
Experimente você mesmo
#include <iostream>
#include "MathUtils.h"
using namespace std;
int main() {
// Ler entradas
int a, b;
double value, low, high;
char ch;
cin >> a;
cin >> b;
cin >> value;
cin >> low;
cin >> high;
cin >> ch;
// TODO: Use o template minimum para encontrar o min de dois inteiros
// Imprima: "Min of <a> and <b>: <result>"
// TODO: Use o template minimum para encontrar o min de 'm' e o caractere de entrada
// Imprima: "Min of m and <char>: <result>"
// TODO: Use o template clamp no valor double
// Imprima: "Clamp <value> to [<low>, <high>]: <result>"
// TODO: Use o template clamp no primeiro inteiro com o intervalo [0, 100]
// Imprima: "Clamp <value> to [0, 100]: <result>"
// TODO: Use o template swapValues nos dois inteiros
// Print: "After swapValues: <a>, <b>"
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos externosBuild e compilação em C++Arquivos de cabeçalho e arquivos-fonteNamespaces e escopoIntrodução à POO em C++Classes vs. objetosO ponteiro 'this'Métodos (funções membro)Atributos (membros de dados)Noções básicas de construtores e destruidoresRevisão - calculadora simples4Propriedades de Classe
Membros de Instância vs. EstáticosGetters e SettersFunções Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRevisão - Gerenciador de Contas Bancárias7Herança
Herança básicaNíveis de acesso da herançaOrdem de chamada de construtor e destrutorSobrescrita de métodosFunções virtuais e VTableHerança múltiplaHerança virtualRevisão - Hierarquia de funcionários10Visão geral da STL
Visão geral e filosofia da STLContêineres da STLIteradoresAlgoritmos da STLFunctors e expressões lambdaRecapitulação - Frequência de palavras13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonFactory e Abstract FactoryPadrão BuilderPadrão ObserverPadrão Strategy2Gerenciamento de Memória
Memória Stack vs. HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Ponteiros Inteligentes em C++RAII em C++Revisão - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de acesso em C++Especificadores de acesso em profundidadeOcultação de informaçõesStruct vs ClasseClasses aninhadas e internasRecapitulação - Sistema de registros de alunos8Polimorfismo
Polimorfismo em compilação vs. execuçãoSobrecarga de funçõesFunções virtuais revisadasFunções virtuais purasClasses abstratasDesign de interfaces em C++Conversão dinâmica e RTTIRecapitulação — Calculadora de formas11Conceitos Avançados de OOP
Composição vs. HerançaMixins via CRTPIdioma PimplApagamento de TiposClasses Enum e Tipagem ForteTratamento de Exceções em OOPHierarquias de Exceções Personalizadas14Padrões de Projeto — Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositeRAII como Padrão3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentoListas de Inicialização do ConstrutorConstrutores DelegantesAprofundamento em DestrutoresRegra dos Três / Cinco / ZeroRevisão - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de FluxoSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçõesTemplates de ClassesEspecialização de TemplatesTemplates VariádicosNoções Básicas de SFINAE e Traits de TiposRecapitulação - Contêiner GenéricoPratique por conta própria: Compilador de C++ online