Da trilha de C++ Este conceito ainda não saiu como card do dia. ir para o card de hoje

C++ Genéricos Intermediário

Templates de classe

Templates de classe permitem escrever uma classe uma única vez e usá-la com diferentes tipos de dados. O compilador gera automaticamente versões especializadas da classe para cada tipo usado. Isso é a base da programação genérica em C++, como visto em std::vector ou std::map.

Além de tipos, templates podem receber parâmetros não-tipo, como valores inteiros ou ponteiros, que são conhecidos em tempo de compilação. Isso permite, por exemplo, criar arrays de tamanho fixo parametrizado.

Com C++17, a dedução de argumentos de template para construtores (CTAD) permite omitir os parâmetros de tipo ao criar objetos, desde que o compilador possa deduzi-los a partir dos argumentos do construtor. Isso simplifica o código e evita redundâncias.

Por fim, membros template são funções ou classes aninhadas que também são templates, permitindo maior flexibilidade dentro de uma classe genérica.

Pontos-chave

  • Template de classe define um modelo de classe parametrizado por tipos ou valores.
  • Parâmetros não-tipo são valores constantes conhecidos em tempo de compilação, como int N.
  • CTAD permite criar objetos sem especificar explicitamente os argumentos de template.
  • Membros template são funções ou classes internas que também podem ser parametrizadas.
  • A instanciação do template ocorre implicitamente quando a classe é usada com um tipo específico.
template_classe.cpp
#include <iostream>
#include <string>

// Template de classe com parâmetro de tipo e parâmetro não-tipo
template <typename T, int N>
class Buffer {
    T dados[N]; // array de tamanho fixo N
public:
    // Construtor padrão
    Buffer() = default;

    // Construtor que preenche com um valor
    Buffer(const T& valor) {
        for (int i = 0; i < N; ++i) dados[i] = valor;
    }

    // Método para acessar elemento
    T& operator[](int i) { return dados[i]; }
    const T& operator[](int i) const { return dados[i]; }

    // Membro template: imprime todos os elementos formatados
    template <typename U>
    void imprimir_como(U prefixo) const {
        for (int i = 0; i < N; ++i)
            std::cout << prefixo << dados[i] << " ";
        std::cout << '\n';
    }
};

int main() {
    // CTAD: deduz T = int, N = 3 a partir do construtor
    Buffer buf(42); // Buffer<int, 3>
    buf[0] = 10;
    buf[1] = 20;
    buf[2] = 30;
    buf.imprimir_como("Valor: ");

    // Especificando explicitamente
    Buffer<std::string, 2> sbuf("Oi");
    sbuf[0] = "Olá";
    sbuf[1] = "Mundo";
    sbuf.imprimir_como("[ ");

    return 0;
}

Exercícios

  1. 1
    Fácil

    Criando um par genérico

    Implemente uma classe template Par que armazena dois valores de tipos possivelmente diferentes. A classe deve ter um construtor que recebe os dois valores, um método primeiro() que retorna o primeiro, um método segundo() que retorna o segundo, e um método trocar() que troca os valores entre si.

    Resolver
  2. 2
    Médio

    Array de tamanho fixo com parâmetro não-tipo

    Crie uma classe template ArrayFixo que recebe um tipo T e um inteiro N como parâmetros não-tipo. A classe deve ter um construtor que preenche todos os elementos com um valor padrão, um método tamanho() que retorna N, e um operador [] para acesso aos elementos. Use CTAD para criar uma instância sem especificar os parâmetros.

    Resolver
  3. 3
    Desafio

    Buffer com CTAD e membro template

    Implemente uma classe template Buffer que armazena um array de tamanho fixo N do tipo T. A classe deve ter um construtor que preenche todos os elementos com um valor, um método tamanho() que retorna N, e um membro template imprimir que recebe um prefixo de qualquer tipo imprimível e imprime todos os elementos. Use CTAD para criar uma instância de Buffer a partir de um valor e um std::integral_constant<int, N>. No main, crie um Buffer com 4 elementos do tipo double preenchidos com 3.14, e outro com 2 elementos do tipo std::string preenchidos com "C++". Imprima os elementos com prefixos diferentes.

    Resolver

Continue estudando