¿Puedo reinterpretar_cast el parámetro de una función constexpr?
Quiero escribir una función evaluada en tiempo de compilación, toma un puntero a una matriz de 4 bytes y genera un int que tiene el mismo patrón de bits que esa matriz. Entonces se me ocurrió:
constexpr int f(const char* p) {
return *reinterpret_cast<int*>(p);
}
Entonces, quiero usar f()así:
switch(x) {
case f("GOOG"):
// do something
case f("MSFT"):
// do something
case f("NIKE"):
// do something
}
Sin embargo, tengo un error del compilador:
error: acceder al valor de '"GOOG"' a través de un glvalue 'int' en un caso de expresión constante f ("GOOG")
- ¿Cómo arreglarlo
f()para que se compile? - ¿Existe una mejor manera de lograr el mismo objetivo?
Respuestas
Felicitaciones, ha activado la tarjeta de captura de aliasing estricto y su código tiene un comportamiento indefinido (si pudiera compilarse).
Hay algunos errores en su código, la versión "correcta" es:
constexpr int f(const char* p) {
return *reinterpret_cast<const int*>(p);
}
reinterpret_castno puede desecharconst.cursor->p¿error de tipografía?
Pero dado const char*que no apunta a un int, al emitirlo se rompe la estricta regla de aliasing. intno es uno de los tipos que pueden alias a otros, solo std::byte, (unsigned) charpuede.
El más limpio sería este:
#include <cstring>
constexpr int f(const char* p) {
int val = 0;
static_assert(sizeof(val)==4); // If the array is 4-byte long.
std::memcpy(&val,p,sizeof val);
return val;
}
Pero std::memcpyno lo es constexpr, incluso en tiempo de ejecución, esto probablemente no tendrá ninguna sobrecarga, el compilador puede reconocer esto y reinterpretar los bytes por sí solo.
Así que vaya con el cambio de bits:
constexpr int f(const char* p) {
int value=0;
using T = decltype (value);
for(std::size_t i =0; i< sizeof(T);++i)
value|= (T)p[i] << (8*i);
return value;
}
int main(){
// @ == 64
// 1077952576 = 01000000 01000000 01000000 01000000
static_assert(f("@@@@") ==1077952576);
}
Ser pedante "@@@@"tiene una longitud de 5, no de 4.