Menu
Coddy logo textTech

Templates de Função

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 máximo de dois inteiros, e depois perceber que precisa da mesma lógica para doubles, e novamente para strings. Sem templates, você escreveria funções quase idênticas para cada tipo. Templates de função resolvem isso permitindo que você escreva a lógica uma vez e faça com que o compilador gere versões específicas para cada tipo automaticamente.

Um template de função usa a palavra-chave template seguida por parâmetros de template 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 esse 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 double

Templates podem ter múltiplos 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=int

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 zero overhead em tempo de execução em comparação com funções virtuais, tornando os templates ideais para código genérico onde o desempenho é crítico.

challenge icon

Desafio

Fácil

Vamos construir um kit de ferramentas utilitárias usando templates de função para criar operações reutilizáveis que funcionam com qualquer tipo compatível. Você organizará suas funções genéricas em um arquivo de cabeçalho e demonstrará a flexibilidade delas em seu 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 (low bound) e um limite superior (high bound). Ela retorna o valor restringido dentro dos limites (retorna low se o valor for menor que low, high se o valor for maior que high, 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):

    1. Primeiro número inteiro
    2. Segundo número inteiro
    3. Um valor double para restringir (clamp)
    4. Limite inferior (double)
    5. Limite superior (double)
    6. Um caractere

    Demonstre seus templates:

    1. Encontrando o mínimo dos dois inteiros e imprimindo: Min of <a> and <b>: <result>
    2. Encontrando o mínimo entre o caractere 'm' e o seu caractere de entrada, imprimindo: Min of m and <char>: <result>
    3. Restringindo (clamping) o valor double e imprimindo: Clamp <value> to [<low>, <high>]: <result>
    4. Restringindo o primeiro inteiro para o intervalo [0, 100] e imprimindo: Clamp <value> to [0, 100]: <result>
    5. 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, 25

Observe como cada função template funciona perfeitamente com inteiros, doubles e caracteres — o compilador gera a versão apropriada para cada tipo que você usa. Sua função swapValues deve modificar as variáveis originais através de referências, demonstrando que templates funcionam com parâmetros de referência assim como funções regulares.

Folha de consulta

Templates de função permitem que você escreva funções genéricas que funcionam com múltiplos tipos. Use a palavra-chave template seguida pelos parâmetros do template:

template <typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

O compilador gera automaticamente versões específicas para cada tipo através da instanciação de template:

maximum(5, 3);        // Gera a versão int
maximum(3.14, 2.71);  // Gera a versão double
maximum('a', 'z');    // Gera a versão char

Você pode especificar explicitamente o tipo quando necessário:

maximum<double>(5, 3.14);  // Força a versão double

Templates suportam múltiplos parâmetros de tipo:

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*

Templates funcionam com parâmetros de referência para modificar valores originais:

template <typename T>
void swapValues(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}

Templates de função fornecem polimorfismo em tempo de compilação com zero de sobrecarga em tempo de execução, tornando-os ideais para código genérico onde a performance é crítica.

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 mínimo de dois inteiros
    // Print: "Min of <a> and <b>: <result>"
    
    // TODO: Use o template minimum para encontrar o mínimo de 'm' e o caractere de entrada
    // Print: "Min of m and <char>: <result>"
    
    // TODO: Use o template clamp no valor double
    // Print: "Clamp <value> to [<low>, <high>]: <result>"
    
    // TODO: Use o template clamp no primeiro inteiro com o intervalo [0, 100]
    // Print: "Clamp <value> to [0, 100]: <result>"
    
    // TODO: Use o template swapValues nos dois inteiros
    // Print: "After swapValues: <a>, <b>"
    
    return 0;
}
quiz iconTeste seus conhecimentos

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