Posso reinterpret_cast o parâmetro de uma função constexpr?
Eu quero escrever uma função avaliada em tempo de compilação, leva um ponteiro para a matriz de 4 bytes e produz um int que tem o mesmo padrão de bits dessa matriz. Então eu vim com:
constexpr int f(const char* p) {
return *reinterpret_cast<int*>(p);
}
Então, eu quero usar f()assim:
switch(x) {
case f("GOOG"):
// do something
case f("MSFT"):
// do something
case f("NIKE"):
// do something
}
No entanto, recebi um erro do compilador:
erro: acessar o valor de '"GOOG"' por meio de um glvalue 'int' em um caso de expressão constante f ("GOOG")
- Como consertar
f()para que ele compile? - Existe uma maneira melhor de atingir o mesmo objetivo?
Respostas
Parabéns, você ativou o cartão de armadilha de aliasing estrito e seu código tem comportamento indefinido (se fosse compilar).
Existem alguns erros em seu código, a versão "correta" é:
constexpr int f(const char* p) {
return *reinterpret_cast<const int*>(p);
}
reinterpret_castnão pode jogar foraconst.cursor->perro de digitação?
Mas, como const char*não aponta para um int, a conversão para ele quebra a regra estrita de aliasing. intnão é um dos tipos que podem apelidar de outros - apenas std::byte, (unsigned) charpodem.
O mais limpo seria 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;
}
Mas std::memcpynão é constexpr, mesmo em tempo de execução provavelmente não terá nenhuma sobrecarga, o compilador pode reconhecer isso e reinterpretar os bytes por conta própria.
Então vá com o bit-shifting:
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);
}
Só para ser pedante "@@@@"tem comprimento 5, não 4.