Menu
Coddy logo textTech

constexpr e consteval

Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 87 de 104.

O C++ permite que computações ocorram em tempo de compilação em vez de tempo de execução, o que pode melhorar significativamente o desempenho. A palavra-chave constexpr (C++11) e a palavra-chave consteval (C++20) oferecem controle sobre quando as expressões são avaliadas.

Uma função constexpr pode ser avaliada em tempo de compilação se receber argumentos constantes, mas também pode ser executada em tempo de execução com entradas não constantes:

#include <iostream>

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

int main() {
    constexpr int compileTime = square(5);  // Avaliado em tempo de compilação
    
    int x = 7;
    int runtime = square(x);  // Avaliado em tempo de execução
    
    std::cout << compileTime << "\n";  // 25
    std::cout << runtime << "\n";      // 49
}

Quando você precisar garantir a avaliação em tempo de compilação, use consteval. Uma função consteval deve produzir uma constante - chamá-la com valores de tempo de execução é um erro de compilação:

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

int main() {
    constexpr int result = factorial(5);  // OK: 120 computado em tempo de compilação
    
    // int x = 5;
    // int bad = factorial(x);  // ERRO: x não é uma constante
}

Você também pode usar constexpr com variáveis e até mesmo construtores de classe, permitindo que objetos inteiros sejam criados em tempo de compilação. Isso é particularmente útil para tabelas de consulta, valores de configuração ou quaisquer dados que não mudam durante a execução do programa.

challenge icon

Desafio

Fácil

Você organizará seu código em três arquivos:

  • MathUtils.h: Defina suas funções matemáticas de tempo de compilação.

    Crie as seguintes funções:

    • cube — uma função constexpr que recebe um int e retorna seu cubo (n * n * n)
    • triangularNumber — uma função constexpr que calcula o enésimo número triangular usando a fórmula n * (n + 1) / 2. Isso deve ser sempre avaliado em tempo de compilação.
    • sumOfSquares — uma função constexpr que recebe dois inteiros e retorna a soma de seus quadrados (a*a + b*b)
  • Config.h: Crie uma estrutura de configuração usando constantes de tempo de compilação.

    Defina uma struct Config com um construtor constexpr que recebe três inteiros: width, height, e depth. Armazene-os como membros públicos. Adicione também um método constexpr chamado volume() que retorna width * height * depth.

    Abaixo da struct, crie uma constante global constexpr chamada DEFAULT_CONFIG inicializada com os valores 10, 20 e 5.

  • main.cpp: Leia dois inteiros da entrada representando valores de tempo de execução.

    Primeiro, demonstre a avaliação em tempo de compilação criando variáveis constexpr:

    • Armazene cube(4) em uma variável constexpr e imprima: Cube of 4: [value]
    • Armazene triangularNumber(10) em uma variável constexpr e imprima: 10th triangular number: [value]
    • Imprima o volume da configuração padrão: Default volume: [value]

    Depois, demonstre que as funções constexpr também podem funcionar em tempo de execução usando seus dois valores de entrada:

    • Chame cube() com a primeira entrada e imprima: Cube of [input]: [result]
    • Chame sumOfSquares() com ambas as entradas e imprima: Sum of squares: [result]

Por exemplo, com as entradas 3 e 4:

Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 3: 27
Sum of squares: 25

Com as entradas 5 e 12:

Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 5: 125
Sum of squares: 169

Folha de consulta

O C++ permite computações em tempo de compilação usando as palavras-chave constexpr (C++11) e consteval (C++20).

Uma função constexpr pode ser avaliada em tempo de compilação com argumentos constantes, mas também é executada em tempo de execução com entradas não constantes:

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

constexpr int compileTime = square(5);  // Evaluated at compile time

int x = 7;
int runtime = square(x);  // Evaluated at runtime

Uma função consteval deve ser avaliada em tempo de compilação. Chamá-la com valores de tempo de execução causa um erro de compilação:

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

constexpr int result = factorial(5);  // OK: computed at compile time

// int x = 5;
// int bad = factorial(x);  // ERROR: x is not a constant

Você pode usar constexpr com variáveis, construtores de classe e métodos para permitir a criação de objetos em tempo de compilação:

struct Config {
    int width, height, depth;
    
    constexpr Config(int w, int h, int d) 
        : width(w), height(h), depth(d) {}
    
    constexpr int volume() const {
        return width * height * depth;
    }
};

constexpr Config config(10, 20, 5);  // Created at compile time

Experimente você mesmo

#include <iostream>
#include "MathUtils.h"
#include "Config.h"

using namespace std;

int main() {
    // Lê dois inteiros da entrada
    int input1, input2;
    cin >> input1;
    cin >> input2;
    
    // TODO: Demonstrar avaliação em tempo de compilação
    // Crie uma variável constexpr armazenando cube(4) e imprima: "Cube of 4: [value]"
    
    // TODO: Crie uma variável constexpr armazenando triangularNumber(10)
    // e imprima: "10th triangular number: [value]"
    
    // TODO: Imprima o volume da configuração padrão: "Default volume: [value]"
    
    // TODO: Demonstrar o uso em tempo de execução de funções constexpr
    // Chame cube() com input1 e imprima: "Cube of [input1]: [result]"
    
    // TODO: Chame sumOfSquares() com ambas as entradas
    // e imprima: "Sum of squares: [result]"
    
    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