Lección 19 · 19 de 20
constexpr y static_assert · C++
Calcule al compilar con constexpr, compruebe condiciones con static_assert y elija código con if constexpr: tamaños, proporciones y tablas en C++.

Una función `constexpr` se puede evaluar al compilar cuando sus argumentos se conocen de antemano. mebibytes(64) y gcd(1920, 1080) no se calculan al ejecutar el programa: el ejecutable ya lleva los resultados. gcd (el máximo común divisor, por el algoritmo de Euclides) es recursiva, y aun así vale.
Desde C++17, una función constexpr puede tener variables y bucles: makeSquares rellena un std::array con los cuadrados del 0 al 9, y squares es una tabla calculada al compilar. Las variables constexpr, como width o cacheSize, son constantes cuyo valor conoce el compilador.
`static_assert` es una comprobación que hace el compilador: si la condición es falsa, el programa no compila y se muestra el mensaje. Aquí garantiza que la pantalla es 16:9, que 64 MiB son 67 108 864 bytes y que la tabla es correcta. Desde C++17 el mensaje es opcional, como en el tercero.
La misma función constexpr sirve en tiempo de ejecución: n no se conoce al compilar, así que gcd(n, 36) se calcula al ejecutar, como cualquier otra función.
`if constexpr` elige una rama al compilar. En la plantilla describe, std::is_integral_v<T> (de <type_traits>) dice si T es un tipo entero: para int solo se compila la primera rama y para double, la segunda.
Código · main.cpp
#include <array>#include <iostream>#include <type_traits>// constexpr: the compiler can work it out while compiling, if the inputs are known.constexpr unsigned long long mebibytes(unsigned long long n) { return n * 1024 * 1024; }constexpr int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }constexpr std::array<int, 10> makeSquares() { // a table built at compile time std::array<int, 10> t{}; for (int i = 0; i < 10; ++i) t[i] = i * i; return t;}constexpr auto squares = makeSquares();constexpr int width = 1920, height = 1080;constexpr unsigned long long cacheSize = mebibytes(64);// static_assert: a check done by the compiler. If it fails, nothing compiles.static_assert(width * 9 == height * 16, "the screen must be 16:9");static_assert(cacheSize == 67108864, "64 MiB in bytes");static_assert(squares[7] == 49 && sizeof(long long) >= 8);template <typename T>void describe(T value) { // if constexpr: only the matching branch is compiled if constexpr (std::is_integral_v<T>) std::cout << value << " is a whole number\n"; else std::cout << value << " is not a whole number\n";}int main() { constexpr int g = gcd(width, height); std::cout << "Aspect ratio " << width / g << ":" << height / g << ", cache " << cacheSize << " bytes\n"; std::cout << "Square of 7 from the table: " << squares[7] << "\n"; int n = 84; // known only at run time: the same function still works std::cout << "gcd(" << n << ", 36) = " << gcd(n, 36) << "\n"; describe(42); describe(2.5);}Salida · c++ -std=c++17 main.cpp -o main && ./main
Aspect ratio 16:9, cache 67108864 bytes Square of 7 from the table: 49 gcd(84, 36) = 12 42 is a whole number 2.5 is not a whole number
Para recordar
constexprpermite calcular al compilar si los datos se conocen.- Una función
constexprtambién funciona con datos del tiempo de ejecución. static_assert(condición, "mensaje")detiene la compilación si falla.if constexprdescarta al compilar la rama que no corresponde.- Lo que se calcula al compilar no cuesta nada al ejecutar.
Ejercicio
Cambie height a 1200 y compile: lea el mensaje del static_assert. Después, escriba una función constexpr factorial(int n) y compruebe con static_assert que factorial(5) == 120.