Menu
Coddy logo textTech

Especialização de Templates

Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy. Lição 66 de 104.

Às vezes, um modelo genérico não funciona bem para todos os tipos. Por exemplo, comparar strings no estilo C com > compara endereços de ponteiros, não o texto em si. A especialização de modelo permite fornecer uma implementação personalizada para tipos específicos, mantendo a versão genérica para todos os outros.

Uma especialização completa substitui o template inteiro para um tipo específico. Você a declara com uma lista de parâmetros de template vazia e especifica o tipo concreto:

// Template primário
template <typename T>
class Printer {
public:
    void print(T value) {
        std::cout << value << std::endl;
    }
};

// Especialização completa para const char*
template <>
class Printer<const char*> {
public:
    void print(const char* value) {
        std::cout << "String: " << value << std::endl;
    }
};

Printer<int> intPrinter;
intPrinter.print(42);           // Saída: 42

Printer<const char*> strPrinter;
strPrinter.print("hello");      // Saída: String: hello

Os modelos de função também podem ser especializados:

template <typename T>
bool isEqual(T a, T b) {
    return a == b;
}

template <>
bool isEqual<const char*>(const char* a, const char* b) {
    return std::strcmp(a, b) == 0;
}

isEqual(5, 5);              // Usa a versão genérica
isEqual("hi", "hi");        // Usa a versão especializada

O compilador sempre prefere a correspondência mais específica — se existir uma especialização para o tipo exato que está sendo usado, ela será escolhida em vez do template genérico.

challenge icon

Desafio

Fácil

Vamos criar um sistema de formatação ciente de tipos que demonstra como a especialização de templates permite personalizar o comportamento para tipos específicos, mantendo uma alternativa genérica para todos os demais.

Você criará dois arquivos para organizar seu código de templates:

  • Formatter.h: Defina um template de classe chamado Formatter que formata valores para exibição. Seu template genérico deve funcionar com qualquer tipo, mas você também criará versões especializadas para tipos que precisam de tratamento personalizado.

    O template principal Formatter deve ter:

    • Um método format() que recebe um valor do tipo T e imprime: Value: <value>

    Crie uma especialização completa para bool que imprima texto legível em vez de 1 ou 0:

    • O método format() deve imprimir: Boolean: true ou Boolean: false

    Crie uma especialização completa para const char* que adicione aspas ao redor das strings:

    • O método format() deve imprimir: String: "<value>"

    Crie também um template de função chamado formatPair que receba dois valores do mesmo tipo e os imprima juntos como: Pair: [<first>, <second>]

    Crie uma especialização de formatPair para const char* que envolva cada string em aspas: Pair: ["<first>", "<second>"]

  • main.cpp: Leia quatro entradas (cada uma em uma linha separada):
    1. Um inteiro
    2. Um double
    3. Um booleano como string (true ou false)
    4. Um valor de string

    Demonstre seus formatadores criando objetos Formatter apropriados e chamando format() para cada tipo:

    1. Formate o inteiro usando Formatter<int>
    2. Formate o double usando Formatter<double>
    3. Formate o booleano usando Formatter<bool> (converta primeiro a entrada de string em um bool)
    4. Formate a string usando Formatter<const char*>

    Em seguida, demonstre a especialização do template de função:

    1. Chame formatPair com dois inteiros: 10 e 20
    2. Chame formatPair com duas strings C: "hello" e "world"

Por exemplo, com as entradas 42, 3.14, true e Hello:

Value: 42
Value: 3.14
Boolean: true
String: "Hello"
Pair: [10, 20]
Pair: ["hello", "world"]

Observe como o template genérico trata inteiros e doubles de forma idêntica, enquanto as versões especializadas para bool e const char* fornecem uma formatação personalizada. O compilador seleciona automaticamente a correspondência mais específica para cada tipo usado.

Experimente você mesmo

#include <iostream>
#include <string>
#include "Formatter.h"

using namespace std;

int main() {
    // Leia as entradas
    int intVal;
    double doubleVal;
    string boolStr;
    string strVal;
    
    cin >> intVal;
    cin >> doubleVal;
    cin >> boolStr;
    cin >> strVal;
    
    // Converta string para bool
    bool boolVal = (boolStr == "true");
    
    // TODO: Crie Formatter<int> e formate o inteiro
    
    // TODO: Crie Formatter<double> e formate o double
    
    // TODO: Crie Formatter<bool> e formate o booleano
    
    // TODO: Crie Formatter<const char*> e formate a string
    // Dica: Use strVal.c_str() para obter const char*
    
    // TODO: Chame formatPair com dois inteiros: 10 e 20
    
    // TODO: Chame formatPair com duas C-strings: "hello" e "world"
    
    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

Pratique por conta própria: Compilador de C++ online