c++ - utilizan - ¿Forzar una expresión constante para ser evaluada durante el tiempo de compilación?
tipos de constantes en programacion (1)
Solo para no dejarlo enterrado en comentarios:
#include <type_traits>
#define COMPILATION_EVAL(e) (std::integral_constant<decltype(e), e>::value)
constexpr int f(int i){return i;}
int main()
{
int x = COMPILATION_EVAL(f(0));
}
EDIT1:
Una advertencia con este enfoque, constexpr
funciones constexpr
pueden aceptar el punto flotante y asignarse a las constexpr
coma flotante constexpr
, pero no se puede usar un tipo de punto flotante como un parámetro de plantilla sin tipo. Además, las mismas limitaciones para otros tipos de literales.
Su lambda funcionaría para eso, pero supongo que necesitaría una captura por defecto para obtener un mensaje de error significativo cuando las cosas no constexpr
pasen a la función. Ese final std::move
es prescindible.
EDIT2:
Err, su enfoque lambda no funciona para mí, me acabo de dar cuenta, cómo puede funcionar, la lambda no es una función constexpr
. No debería funcionar para ti también.
Parece que realmente no hay forma de constexpr
sino inicializando una variable constexpr
en el ámbito local.
EDIT3:
Oh, está bien, mi mal, el propósito de la lambda es solo la evaluación. Entonces está funcionando para eso. Su resultado, en cambio, es que no se puede usar para seguir otro tiempo de compilación eval.
EDIT4:
En C ++ 17, ahora se puede usar constexpr
en contextos constexpr
, por lo que se elimina la limitación a la que se hace referencia en EDIT2 / EDIT3. Entonces la solución lambda es la correcta. Vea este comentario para más información.
Hace unos días pregunté por qué criterio el compilador decide si se debe o no calcular una función constexpr durante el tiempo de compilación.
¿Cuándo se evalúa una función constexpr en tiempo de compilación?
Como resultado, un constexpr solo se evalúa durante el tiempo de compilación, si todos los parámetros son expresiones constantes y la variable a la que lo está asignando también es una expresión constante.
template<typename base_t, typename expo_t>
constexpr base_t POW(base_t base, expo_t expo)
{
return (expo != 0 )? base * POW(base, expo -1) : 1;
}
template<typename T>
void foobar(T val)
{
std::cout << val << std::endl;
}
int main(int argc, char** argv)
{
foobar(POW((unsigned long long)2, 63));
return 0;
}
Si lo que me dijeron es cierto, este ejemplo de código es muy impráctico, ya que foobar no toma un constexpr (no se puede usar consexpr para los parámetros por alguna razón), POW se evalúa durante el tiempo de ejecución, aunque hubiera sido posible para calcularlo durante el tiempo de compilación. La solución obvia para forzar una evaluación en tiempo de compilación sería esta:
auto expr = POW((unsigned long long)2, 63);
foobar(expr);
Sin embargo, esto me obliga a utilizar una línea adicional de código, que no debería ser necesaria cada vez que quiero asegurarme de que se evalúa un constexpr durante el tiempo de compilación. Para hacer esto un poco más conveniente, he llegado a la siguiente macro dudosa:
#define FORCE_CT_EVAL(func) [](){constexpr auto ___expr = func; return std::move(___expr);}()
foobar(FORCE_CT_EVAL(POW((unsigned long long)2, 63)));
A pesar de que funciona bien, siento que algo no está bien. ¿Crear un rendimiento de impacto lambda anónimo? ¿La referencia de return by rvalue mueve realmente la expresión al parámetro de la función? ¿Cómo afecta std :: move el rendimiento? ¿Hay una mejor solución de un trazador de líneas para esto?