Historia de la pregunta
C++ originalmente solo soportaba macros (#define) y constantes (const). Sin embargo, para definir valores en tiempo de compilación, esto no era suficiente. En C++11 se introdujo la palabra clave constexpr, que permite calcular valores en la etapa de compilación, y no solo durante la ejecución del programa.
Problema
Antes de la aparición de constexpr, muchas tareas debían resolverse utilizando macros (un sustituto textual tosco sin seguridad de tipo) o con const, que no siempre garantizaba la evaluación de la expresión en tiempo de compilación. Esto dificultaba la optimización del programa y conducía a un comportamiento menos predecible.
Solución
constexpr garantiza al compilador que la expresión declarada siempre será calculada en la compilación, si es posible. Esto se usa para declarar funciones, variables y hasta constructores y métodos de clases que se pueden calcular de forma segura y eficiente en tiempo de compilación.
Ejemplo de código:
constexpr int Square(int x) { return x * x; } constexpr int size = Square(5); // size se calcula en tiempo de compilación const int arr[size] = {}; // se puede usar como tamaño de array
Características clave:
¿Se puede usar cualquier función como constexpr?
No. La función debe cumplir con una serie de restricciones: ser lo suficientemente simple, contener una sola instrucción return (hasta C++14) o solo código constante (desde C++14 en adelante).
constexpr int f(int x) { return x + 2; } // ok constexpr int g(int x) { int y = x + 2; return y; } // hasta C++14: ¡no compila! después — se puede
¿Pueden todas las variables constexpr calcularse en tiempo de compilación?
No. Si se utiliza un valor no constante durante la inicialización o si la expresión no se puede calcular en tiempo de compilación, habrá un error.
int val; // constexpr int x = f(val); // Error: ¡val no está inicializado!
¿Cuál es la diferencia entre constexpr y const?
const solo garantiza la imposibilidad de modificación, pero no asegura la evaluación en tiempo de compilación. constexpr requiere que se calcule el valor en tiempo de compilación (si es posible).
const int x = time(nullptr); // ok, pero se calcula en tiempo de ejecución constexpr int y = 42; // ok, se calcula en tiempo de compilación
El desarrollador utiliza #define PI 3.14 para todos los cálculos del área de un círculo.
Ventajas:
Desventajas:
El desarrollador utiliza constexpr double PI = 3.141592653589793; y funciones constexpr de plantilla para los cálculos.
Ventajas:
Desventajas: