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 se realicen 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) te permiten controlar cuándo se evalúan las expresiones.
Una función constexpr puede evaluarse 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, usa 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 con constructores de clases, lo que permite crear objetos completos en tiempo de compilación. Esto es especialmente útil para tablas de búsqueda, valores de configuración o cualquier dato que no cambie durante la ejecución del programa.
Desafío
FácilOrganizará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ónconstexprque toma uninty devuelve su cubo (n * n * n)triangularNumber: una funciónconstexprque calcula el n.º número triangular usando la fórmula n * (n + 1) / 2. En esta tarea, solo la llamamos en un contexto de tiempo de compilación y almacenamos su resultado en una variableconstexpr.sumOfSquares: una funciónconstexprque toma dos enteros y devuelve la suma de sus cuadrados (a*a + b*b)
Config.h: Crea una estructura de configuración usando constantes de tiempo de compilación.Define una estructura
Configcon un constructorconstexprque toma tres enteros:width,heightydepth. Guárdalos como miembros públicos. Añade también un métodoconstexprllamadovolume()que devuelve width * height * depth.Debajo de la estructura, crea una constante global
constexprllamadaDEFAULT_CONFIGinicializada 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 predeterminada:
Default volume: [value]
Después, demuestra que las funciones
constexprtambién pueden funcionar en tiempo de ejecución usando los 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]
- Almacena
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: 25Con las entradas 5 y 12:
Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 5: 125
Sum of squares: 169Pruébalo tú mismo
#include <iostream>
#include "MathUtils.h"
#include "Config.h"
using namespace std;
int main() {
// Lee dos números enteros de la entrada
int input1, input2;
cin >> input1;
cin >> input2;
// TODO: Demuestra 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 predeterminada: "Default volume: [value]"
// TODO: Demuestra el uso de funciones constexpr en tiempo de ejecución
// 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;
}
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
1Fundamentos de la POO
Archivos externosCompilación y construcción en C++Archivos de cabecera y archivos fuenteEspacios de nombres y ámbitoIntroducción a la POO en C++Clases y objetosEl puntero 'this'Métodos (funciones miembro)Atributos (miembros de datos)Fundamentos de constructores y destructoresRepaso: calculadora sencilla4Propiedades de clase
Miembros de instancia vs. estáticosGetters y settersFunciones miembro constPalabra clave mutableMétodos y variables estáticosFunciones y clases friendRepaso: gestor de cuentas bancarias7Herencia
Herencia básicaNiveles de acceso en la herenciaOrden de llamada de constructores y destructoresSobrescritura de métodosFunciones virtuales y VTableHerencia múltipleHerencia virtualRepaso: jerarquía de empleados2Gestión de memoria
Memoria de pila vs. heapPunteros y referenciasMemoria dinámica (new/delete)Punteros inteligentes en C++RAII en C++Repaso: gestor de arreglos dinámicos5Encapsulación
Especificadores de acceso en C++Especificadores de acceso en profundidadOcultación de informaciónStruct vs. classClases anidadas e internasRepaso: sistema de registros de estudiantes8Polimorfismo
Polimorfismo en compilación y en tiempo de ejecuciónSobrecarga de funcionesRepaso de las funciones virtualesFunciones virtuales purasClases abstractasDiseño de interfaces en C++Conversión dinámica y RTTIRepaso: calculadora de formas11Conceptos avanzados de POO
Composición frente a herenciaMixins mediante CRTPIdiom PimplBorrado de tiposClases enum y tipado fuerteManejo de excepciones en POOJerarquías de excepciones personalizadas14Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositeRAII como patrón3Constructores y destructores
Constructor predeterminadoConstructor con parámetrosConstructor de copiaConstructor de movimientoListas de inicialización del constructorConstructores delegadosAnálisis detallado del destructorRegla de tres / cinco / ceroRepaso: clase String6Sobrecarga de operadores
Introducción a la sobrecarga de operadoresSobrecarga de operadores aritméticosSobrecarga de operadores de comparaciónOperadores de flujoSobrecarga del operador de asignaciónSobrecarga de los operadores [] y ()Operadores de conversión de tipoRepaso: clase Matrix9Plantillas
Plantillas de funcionesPlantillas de clasesEspecialización de plantillasPlantillas variádicasFundamentos de SFINAE y rasgos de tiposRepaso: contenedor genérico12Características modernas de C++
Semántica de movimiento y rvaluesReenvío perfectoExpresiones lambda en profundidadstd::function y std::bindconstexpr y constevalDescomposición estructuradaoptional, variant, anyPractica por tu cuenta: Compilador de C++ online