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.
#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;
}