💻 Exemplos: Capítulo 13: Templates Modernos, Cláusula Requires e C++20 Concepts

Especialização em Sistemas com C++ • Demonstrações Práticas Compiláveis


🎯 Objetivo dos Exemplos

Apresentar a programação genérica moderna com restrições formais de tipos em tempo de compilação: declaração de concept, restrições com a cláusula requires, eliminação de erros crípticos de template (SFINAE / template error dumps) e criação de funções genéricas altamente expressivas e otimizadas sem custo de runtime.


1. Código Fonte Completo (main.cpp)

/**
 * @file main.cpp
 * @brief Metaprogramação genérica moderna com C++20 Concepts e cláusula requires.
 */

#include <iostream>
#include <concepts>
#include <string>
#include <vector>

// 1. Definição de Concepts Personalizados no C++20

// Concept que exige que o tipo seja numérico (integral ou ponto flutuante)
template <typename T>
concept Numerico = std::integral<T> || std::floating_point<T>;

// Concept que exige que o tipo possua método serialize() retornando std::string
template <typename T>
concept Serializavel = requires(T a) {
    { a.serialize() } -> std::same_as<std::string>;
};

// 2. Função com Restrição de Concept (Sintaxe Direta de Parâmetro)
template <Numerico T>
T calcular_potencia_sinal(T amplitude, T ganho) {
    return amplitude * ganho;
}

// 3. Função com Cláusula requires Adicional
template <typename T>
    requires Serializavel<T>
void persistir_telemetria(const T& registro) {
    std::cout << "[Storage] Gravando payload serializado: " << registro.serialize() << '\n';
}

// Estruturas de Teste
struct SensorLog {
    int id;
    double temperatura;

    std::string serialize() const {
        return "SensorLog{id=" + std::to_string(id) + 
               ", temp=" + std::to_string(temperatura) + "}";
    }
};

int main() {
    std::cout << "=== CAPÍTULO 13: TEMPLATES E C++20 CONCEPTS ===" << '\n';

    // 4. Invocação de função restrita a tipos numéricos
    auto pot_inteira = calcular_potencia_sinal(10, 5);
    auto pot_real    = calcular_potencia_sinal(3.5, 2.0);

    std::cout << "Potencia Inteira: " << pot_inteira << " W" << '\n';
    std::cout << "Potencia Real:    " << pot_real << " W" << '\n';

    // Se tentássemos: calcular_potencia_sinal("erro", "str");
    // O compilador rejeitaria com mensagem amigável: 'constraints not satisfied'!

    // 5. Invocação de função com Concept Serializavel
    SensorLog log_temperatura{ 402, 78.4 };
    persistir_telemetria(log_temperatura);

    // 6. Restrição Ad-Hoc com requires em Função Lambda (C++20)
    auto formatador_hex = [](std::integral auto valor) {
        std::cout << "Valor Hex: 0x" << std::hex << valor << std::dec << '\n';
    };

    formatador_hex(255);
    formatador_hex(65535LL);

    return 0;
}

2. Instruções de Compilação e Execução

# Compilação com GCC / Clang
g++ -std=c++20 -Wall -Wextra -O2 main.cpp -o app_concepts
./app_concepts

# Compilação com MSVC
cl /std:c++20 /EHsc /W4 /O2 main.cpp /Fe:app_concepts.exe
.\app_concepts.exe

3. Saída Esperada no Terminal

=== CAPÍTULO 13: TEMPLATES E C++20 CONCEPTS ===
Potencia Inteira: 50 W
Potencia Real:    7 W
[Storage] Gravando payload serializado: SensorLog{id=402, temp=78.400000}
Valor Hex: 0xff
Valor Hex: 0xffff