c++ constexpr c++20

c++ - Enteros constantes y evaluación constante



constexpr c++20 (1)

¿No es divertido la evaluación constante?

Hay algunos lugares en el lenguaje donde tratamos de hacer una evaluación constante y si eso falla, recurrimos a la evaluación no constante. La inicialización estática es uno de esos lugares, la inicialización de enteros constantes es otro.

Que pasa con:

int const i = f();

es que esto podría ser una evaluación constante, pero no necesariamente tiene que serlo. Debido a que los enteros constantes (no constexpr ) todavía se pueden usar como expresiones constantes, si cumplen con todas las demás condiciones, tenemos que intentarlo. Por ejemplo:

const int n = 42; // const, not constexpr std::array<int, n> arr; // n is a constant expression, this is ok

Así que intentemos hacerlo, llamamos f() como una expresión constante. En este contexto, std::is_constant_evaluated() es true , por lo que golpeamos la rama con el throw y terminamos fallando. No se puede throw durante la evaluación constante, por lo que nuestra evaluación constante falla.

Pero luego retrocedemos e intentamos nuevamente, esta vez llamando a f() como una expresión no constante (es decir, std::is_constant_evaluated() es false ). Esta ruta tiene éxito, dándonos 1 , por lo que se inicializa con el valor 1 . Pero notablemente, no soy una expresión constante en este punto. ¡Un static_assert(i == 1) posterior static_assert(i == 1) estaría mal formado porque el inicializador de i no era una expresión constante! Aunque la ruta de inicialización no constante sucede (de lo contrario) satisface por completo los requisitos de una expresión constante.

Tenga en cuenta que si lo intentamos:

constexpr int i = f();

Esto habría fallado porque no podemos recurrir a la inicialización no constante.

Considere el siguiente programa:

#include <iostream> #include <type_traits> constexpr int f() { if (std::is_constant_evaluated()) return -1; else return 1; } int main() { int const i = f(); std::cout << i; }

Imprime -1 cuando se ejecuta (wandbox).

Sin embargo, si hago que la función throw cuando se evalúa en tiempo de compilación ::

#include <iostream> #include <type_traits> constexpr int f() { if (std::is_constant_evaluated()) throw -1; // <----------------------- Changed line else return 1; } int main() { int const i = f(); std::cout << i; }

compila bien y genera 1 (wandbox). ¿Por qué no recibí un error de compilación en su lugar?