Menu
Coddy logo textTech

constexpr y consteval

Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy — lección 87 de 104.

C++ permite que los cálculos ocurran en tiempo de compilación en lugar de en tiempo de ejecución, lo que puede mejorar significativamente el rendimiento. La palabra clave constexpr (C++11) y la palabra clave consteval (C++20) le brindan control sobre cuándo se evalúan las expresiones.

Una función constexpr puede ser evaluada en tiempo de compilación si se le proporcionan argumentos constantes, pero también puede ejecutarse en tiempo de ejecución con entradas no constantes:

#include <iostream>

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

int main() {
    constexpr int compileTime = square(5);  // Evaluado en tiempo de compilación
    
    int x = 7;
    int runtime = square(x);  // Evaluado en tiempo de ejecución
    
    std::cout << compileTime << "\n";  // 25
    std::cout << runtime << "\n";      // 49
}

Cuando necesites garantizar la evaluación en tiempo de compilación, utiliza consteval. Una función consteval debe producir una constante; llamarla con valores en tiempo de ejecución es un error de compilación:

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

int main() {
    constexpr int result = factorial(5);  // OK: 120 calculado en tiempo de compilación
    
    // int x = 5;
    // int bad = factorial(x);  // ERROR: x no es una constante
}

También puedes usar constexpr con variables e incluso constructores de clase, permitiendo que se creen objetos enteros en tiempo de compilación. Esto es particularmente útil para tablas de búsqueda, valores de configuración o cualquier dato que no cambie durante la ejecución del programa.

challenge icon

Desafío

Fácil

Organizarás tu código en tres archivos:

  • MathUtils.h: Define tus funciones matemáticas de tiempo de compilación.

    Crea las siguientes funciones:

    • cube — una función constexpr que toma un int y devuelve su cubo (n * n * n)
    • triangularNumber — una función constexpr que calcula el n-ésimo número triangular usando la fórmula n * (n + 1) / 2. Esta debe evaluarse siempre en tiempo de compilación.
    • sumOfSquares — una función constexpr que toma dos enteros y devuelve la suma de sus cuadrados (a*a + b*b)
  • Config.h: Crea una estructura de configuración utilizando constantes de tiempo de compilación.

    Define una estructura Config con un constructor constexpr que tome tres enteros: width, height y depth. Almacénalos como miembros públicos. También añade un método constexpr llamado volume() que devuelva width * height * depth.

    Debajo de la estructura, crea una constante global constexpr llamada DEFAULT_CONFIG inicializada con los valores 10, 20 y 5.

  • main.cpp: Lee dos enteros de la entrada que representen valores de tiempo de ejecución.

    Primero, demuestra la evaluación en tiempo de compilación creando variables constexpr:

    • Almacena cube(4) en una variable constexpr e imprime: Cube of 4: [value]
    • Almacena triangularNumber(10) en una variable constexpr e imprime: 10th triangular number: [value]
    • Imprime el volumen de la configuración por defecto: Default volume: [value]

    Luego, demuestra que las funciones constexpr también pueden funcionar en tiempo de ejecución utilizando tus dos valores de entrada:

    • Llama a cube() con la primera entrada e imprime: Cube of [input]: [result]
    • Llama a sumOfSquares() con ambas entradas e imprime: Sum of squares: [result]

Por ejemplo, con las entradas 3 y 4:

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

Con las entradas 5 y 12:

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

Hoja de referencia

C++ permite realizar cálculos en tiempo de compilación utilizando las palabras clave constexpr (C++11) y consteval (C++20).

Una función constexpr puede ser evaluada en tiempo de compilación con argumentos constantes, pero también se ejecuta en tiempo de ejecución con entradas que no son constantes:

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

constexpr int compileTime = square(5);  // Evaluada en tiempo de compilación

int x = 7;
int runtime = square(x);  // Evaluada en tiempo de ejecución

Una función consteval debe ser evaluada en tiempo de compilación. Llamarla con valores de tiempo de ejecución provoca un error de compilación:

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

constexpr int result = factorial(5);  // OK: calculada en tiempo de compilación

// int x = 5;
// int bad = factorial(x);  // ERROR: x no es una constante

Puedes usar constexpr con variables, constructores de clase y métodos para permitir la creación de objetos en tiempo de compilación:

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);  // Creada en tiempo de compilación

Pruébalo tú mismo

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

using namespace std;

int main() {
    // Lee dos enteros de la entrada
    int input1, input2;
    cin >> input1;
    cin >> input2;
    
    // TODO: Demostrar la evaluación en tiempo de compilación
    // Crea una variable constexpr que almacene cube(4) e imprime: "Cube of 4: [value]"
    
    // TODO: Crea una variable constexpr que almacene triangularNumber(10)
    // e imprime: "10th triangular number: [value]"
    
    // TODO: Imprime el volumen de la configuración por defecto: "Default volume: [value]"
    
    // TODO: Demostrar el uso en tiempo de ejecución de funciones constexpr
    // Llama a cube() con input1 e imprime: "Cube of [input1]: [result]"
    
    // TODO: Llama a sumOfSquares() con ambas entradas
    // e imprime: "Sum of squares: [result]"
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos