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 durante la 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 recibe 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 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 evaluables en tiempo de compilación.Crea las siguientes funciones:
cube: una funciónconstexprque recibe uninty devuelve su cubo (n * n * n)triangularNumber: una funciónconstexprque calcula el número triangular n usando la fórmula n * (n + 1) / 2. En esta tarea solo la llamaremos en un contexto de tiempo de compilación, almacenando su resultado en una variableconstexpr.sumOfSquares: una funciónconstexprque recibe 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 recibe tres enteros:width,heightydepth. Almacénalos como miembros públicos. Añade también un métodoconstexprllamadovolume()que devuelva width * height * depth.Debajo de la estructura, crea una constante global
constexprllamadaDEFAULT_CONFIG, inicializada con los valores 10, 20 y 5.main.cpp: Lee dos enteros de la entrada que representen valores en 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 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]
- 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 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: Create a constexpr variable storing triangularNumber(10)
// and print: "10th triangular number: [value]"
// TODO: Print the default config's volume: "Default volume: [value]"
// TODO: Demuestra el uso en tiempo de ejecución de funciones constexpr
// Llama a cube() con input1 e imprime: "Cube of [input1]: [result]"
// TODO: Call sumOfSquares() with both inputs
// and print: "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 OOP
Archivos externosConstrucción y compilación en C++Archivos de cabecera y archivos fuenteNamespaces y alcanceIntroducción a OOP en C++Clases vs ObjetosEl puntero 'this'Métodos (Funciones miembro)Atributos (Miembros de datos)Conceptos básicos de Ctors y DtorsResumen - Calculadora simple4Propiedades de clase
Miembros de instancia vs. estáticosGetters y SettersFunciones miembro constPalabra clave mutableMétodos y variables estáticosFunciones y clases amigasResumen - Gestor de cuentas bancarias7Herencia
Herencia básicaNiveles de acceso en la herenciaOrden de llamada de Ctor y DtorSobrescritura de métodosFunciones virtuales y VTableHerencia múltipleHerencia virtualResumen - Jerarquía de empleados2Gestión de memoria
Memoria Stack vs HeapPunteros y referenciasMemoria dinámica (new/delete)Punteros inteligentes en C++RAII en C++Resumen - Gestor de arrays dinámicos5Encapsulamiento
Especificadores de acceso en C++Especificadores de acceso en profundidadOcultamiento de informaciónStruct vs ClassClases anidadas e internasResumen - Sistema de registros de estudiantes8Polimorfismo
Polimorfismo: Compilación vs. Tiempo de ejecuciónSobrecarga de funcionesFunciones virtuales revisadasFunciones virtuales purasClases abstractasDiseño de interfaces en C++Dynamic Casting y RTTIResumen: Calculadora de figuras11Conceptos avanzados de POO
Composición vs. HerenciaMixins mediante CRTPIdioma PimplBorrado de tiposEnum Classes 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 por defectoConstructor parametrizadoConstructor de copiaConstructor de movimientoListas de inicialización del constructorConstructores delegadosAnálisis profundo del destructorRegla de tres / cinco / ceroResumen - Clase String6Sobrecarga de operadores
Introducción a la sobrecarga de operadoresSobrecarga de operadores aritméticosSobrecarga de operadores de comparaciónOperadores de flujo (Stream)Sobrecarga del operador de asignaciónSobrecarga de los operadores [] y ()Operadores de conversión de tiposResumen - Clase Matrix9Plantillas
Plantillas de funcionesPlantillas de clasesEspecialización de plantillasPlantillas variádicasConceptos básicos de SFINAE y Type TraitsResumen - Contenedor genérico12Características de C++ moderno
Semántica de movimiento y RvaluesReenvío perfectoExpresiones Lambda en profundidadstd::function y std::bindconstexpr y constevalBindings estructuradosoptional, variant, anyPractica por tu cuenta: Compilador de C++ online