C++: Introdução à Metaprogramação de Templates

Última atualização: 2026-08-26

Na lição 46 aprendemos sobre smart pointers avançados.

Agora, vamos tocar na "magia negra" do C++ — metaprogramação de templates.

Metaprogramação de templates é uma técnica que executa código em tempo de compilação, o que pode melhorar significativamente o desempenho em tempo de execução.


1. Visão Geral da Metaprogramação de Templates

(1) 1.1 O que é Metaprogramação de Templates?

Metaprogramação de Templates (TMP) é uma técnica que usa templates para realizar computações em tempo de compilação.

Características:


(2) 1.2 Por que Usar Metaprogramação de Templates?

Vantagem Descrição
Desempenho Computação em tempo de compilação, mais rápido em tempo de execução
Segurança de tipo Verificação de tipo em tempo de compilação
Genericidade Escrever código verdadeiramente genérico


2. Computação em Tempo de Compilação

(1) 2.1 Fatorial em Tempo de Compilação

Exemplo: Calculando fatorial com templates (Dificuldade ⭐⭐⭐)

▶ Exemplo 1: Exemplo de Código (Dificuldade ⭐)

TEXT 📖 Somente leitura
#include <iostream>

// Primary template
template<int N>
struct Factorial {
 static const int value = N * FactorialN-1::value;
};

// Specialization: termination condition
template<>
struct Factorial<0> {
 static const int value = 1;
};

int main() {
 std::cout << "5! = " << Factorial<5>::value << std::endl; // 120
 // Result computed at compile time, used directly at runtime
 
 return 0;
}

Saída:

TEXT 📖 Somente leitura
5! = 

▶ Exemplo 2: Exemplo de Código (Dificuldade ⭐)

💡 Dica:


(2) 2.2 Funções constexpr (C++11, Recomendado)

O C++11 introduziu constexpr, tornando a computação em tempo de compilação mais simples.

Exemplo: Calculando fatorial com constexpr (Dificuldade ⭐⭐)

CPP
#include <iostream>

constexpr int factorial(int n) {
 return n <= 1 ? 1 : n * factorial(n - 1);
}

int main() {
 constexpr int result = factorial(5); // Compile-time computation
 std::cout << "5! = " << result << std::endl; // 120
 
 return 0;
}

Saída:

TEXT 📖 Somente leitura
5! = 

💡 Dica:



3. Type Traits

(1) 3.1 O que são Type Traits?

Type Traits são técnicas para consultar ou modificar informações de tipo em tempo de compilação.

Exemplo: Usando type_traits para verificar tipos (Dificuldade ⭐⭐)

TEXT 📖 Somente leitura
#include <iostream>
#include <type_traits>

int main() {
 std::cout << std::is_integralint::value << std::endl; // 1 (true)
 std::cout << std::is_integraldouble::value << std::endl; // 0 (false)
 std::cout << std::is_pointer<int*>::value << std::endl; // 1 (true)
 
 return 0;
}

(2) 3.2 Type Traits Personalizados

Exemplo: Detectando se uma classe tem uma função membro (Dificuldade ⭐⭐⭐⭐)

CPP
#include <iostream>
#include <type_traits>

// Detect whether there is a serialize member function
template<typename T>
struct has_serialize {
private:
 template<typename U>
 static auto test(int) -> decltype(std::declvalU().serialize(), std::true_type{});
 
 template<typename U>
 static std::false_type test(...);
 
public:
 static const bool value = decltype(testT(0))::value;
};

struct Person {
 void serialize() {}
};

int main() {
 std::cout << has_serializePerson::value << std::endl; // 1 (true)
 std::cout << has_serializeint::value << std::endl; // 0 (false)
 
 return 0;
}


4. SFINAE

(1) 4.1 O que é SFINAE?

SFINAE (Substitution Failure Is Not An Error): Quando a substituição de argumentos de template falha, não é um erro — o compilador tentará outras sobrecargas.

Finalidade: Selecionar diferentes sobrecargas de função com base nas características do tipo.


(2) 4.2 Exemplo: SFINAE para Selecionar Sobrecargas (Dificuldade ⭐⭐⭐⭐)

TEXT 📖 Somente leitura
#include <iostream>
#include <type_traits>
#include <string>

// Version 1: for integer types
template<typename T>
typename std::enable_if<std::is_integralT::value, std::string>::type
toString(T value) {
 return std::to_string(value) + " (integer)";
}

// Version 2: for other types
template<typename T>
typename std::enable_if<!std::is_integralT::value, std::string>::type
toString(T value) {
 return "Not an integer";
}

int main() {
 std::cout << toString(42) << std::endl; // 42 (integer)
 std::cout << toString(3.14) << std::endl; // Not an integer
 
 return 0;
}

Saída:

TEXT 📖 Somente leitura
(program output)


5. Templates Variádicos

(1) 5.1 O que são Templates Variádicos?

Templates Variádicos permitem que templates aceitem um número arbitrário de argumentos.

Exemplo: Imprimindo qualquer número de argumentos (Dificuldade ⭐⭐⭐)

CPP
#include <iostream>

// Recursion termination function
void print() {
 std::cout << std::endl;
}

// Recursive print
template<typename T, typename... Args>
void print(T first, Args... rest) {
 std::cout << first << " ";
 print(rest...); // Recursive call
}

int main() {
 print(1, 2.5, "hello", 'a');
 // Output: 1 2.5 hello a
 
 return 0;
}


6. Expressões Fold do C++17

(1) 6.1 Uso Básico

O C++17 introduziu expressões fold, que simplificam templates variádicos.

Exemplo: Somatório (Dificuldade ⭐⭐)

CPP
#include <iostream>

template<typename... Args>
auto sum(Args... args) {
 return (args + ...); // Fold expression
}

int main() {
 std::cout << sum(1, 2, 3, 4, 5) << std::endl; // 15
 return 0;
}

▶ Exemplo 3: Computação em Tempo de Compilação com constexpr (Dificuldade ⭐)

CPP
#include <iostream>

// constexpr functions are evaluated at compile time
constexpr int square(int n) {
    return n * n;
}

constexpr int cube(int n) {
    return n * n * n;
}

int main() {
    // Compile-time computation, results embedded directly
    constexpr int sq = square(5);
    constexpr int cb = cube(3);

    std::cout << "5^2 = " << sq << std::endl;
    std::cout << "3^3 = " << cb << std::endl;

    // Static assertions verify compile-time evaluation
    static_assert(sq == 25, "square(5) should be 25");
    static_assert(cb == 27, "cube(3) should be 27");

    return 0;
}
▶ Experimente

Saída:

TEXT 📖 Somente leitura
5^2 = 
3^3 = 

❓ Perguntas Frequentes

P: Metaprogramação de templates é difícil de aprender? R: Sim. É recomendado dominar templates básicos antes de aprender metaprogramação. A maioria dos projetos não precisa de metaprogramação.


P: Quando devo usar metaprogramação de templates? R: - Escrevendo bibliotecas (como a STL) - Quando precisa de desempenho extremo - Quando precisa de verificação de tipo em tempo de compilação


P: constexpr pode substituir metaprogramação de templates? R: Parcialmente. O C++14/17 expandiu constexpr, e muitas computações em tempo de compilação agora podem ser implementadas com funções constexpr.


📖 Resumo

Tópico Pontos-chave
Computação em tempo de compilação Recursão de template ou constexpr
Type traits Biblioteca type_traits
SFINAE Selecionar sobrecargas com base no tipo
Templates variádicos Aceitar número arbitrário de argumentos
Expressões fold C++17, simplifica templates variádicos

📝 Exercícios

  1. Básico (Dificuldade ⭐): Escreva uma função constexpr para calcular fatorial, avaliada em tempo de compilação. Verifique o resultado usando static_assert.

  2. Intermediário (Dificuldade ⭐⭐): Use std::enable_if para implementar um template de função que só é habilitado quando T é um tipo inteiro. Tipos de ponto flutuante devem causar erro de compilação.

  3. Desafio (Dificuldade ⭐⭐⭐): Use templates variádicos para implementar uma função print_all que aceita qualquer número e tipo de argumentos e os imprime um a um. Dica: Use expansão recursiva ou expressões fold (C++17).



Próxima lição: Novos Recursos do C++17/20 (#48)

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%