En su reciente charla "Punking de tipo en C ++ moderno", Timur Doumler dijo que std::bit_castno se puede usar para convertir un bit floaten un unsigned char[4]porque las matrices de estilo C no se pueden devolver de una función. Deberíamos usar std::memcpyo esperar hasta C ++ 23 (o posterior) cuando algo así reinterpret_cast<unsigned char*>(&f)[i]esté bien definido.
En C ++ 20, ¿podemos usar un std::arraycon std::bit_cast,
float f = /* some value */;
auto bits = std::bit_cast<std::array<unsigned char, sizeof(float)>>(f);
en lugar de una matriz de estilo C para obtener bytes de a float?
fuente

struct X { unsigned char elems[5]; };satisface la regla que está citando. Ciertamente se puede inicializar en una lista con hasta 4 elementos. Puede también ser inicializado lista con los 5 elementos. No creo que ningún implementador de biblioteca estándar odie a las personas lo suficiente como para hacer esto, pero creo que es técnicamente conforme.elems[5]. Y en ese punto no puedo ver cómo podrías terminar con un agregadosizeof(array<char, sizeof(T)>) != sizeof(T)¿ dónde ?struct X { unsigned char c1, c2, c3, c4; };ostruct X { unsigned char elems[4]; };, por lo tanto, aunque los caracteres deben ser los elementos de ese agregado, esto les permite ser elementos agregados directos o elementos de un solo sub-agregado.P -> Qno implica nada sobre el caso donde!Parrayno tenga relleno. Las implementaciones de este pueden no tener relleno (y cualquier implementación que lo haga debe considerarse disfuncional), pero no hay garantía de que enarraysí no lo tenga.La respuesta aceptada es incorrecta porque no tiene en cuenta los problemas de alineación y relleno.
Por [matriz] / 1-3 :
El estándar en realidad no requiere
std::arraytener exactamente un miembro de datos público de tipoT[N], por lo que en teoría es posible quesizeof(To) != sizeof(From)ois_trivially_copyable_v<To>.Sin embargo, me sorprendería si esto no funciona en la práctica.
fuente
Si.
Según el documento que describe el comportamiento
std::bit_casty la implementación propuesta en la medida en que ambos tipos tengan el mismo tamaño y se puedan copiar trivialmente, el reparto debe ser exitoso.Una implementación simplificada de
std::bit_castdebería ser algo como:Desde un flotante (4 bytes) y una matriz de
unsigned charconsize_of(float)respecto a todas esas afirmaciones, se realizará el subyacentestd::memcpy. Por lo tanto, cada elemento en la matriz resultante será un byte consecutivo del flotante.Para probar este comportamiento, escribí un pequeño ejemplo en Compiler Explorer que puedes probar aquí: https://godbolt.org/z/4G21zS . El float 5.0 se almacena correctamente como una matriz de bytes (
Ox40a00000) que corresponde a la representación hexadecimal de ese número flotante en Big Endian .fuente
std::arrayestá garantizado que no tiene bits de relleno, etc.?auto bits = reinterpret_cast<std::array<unsigned char, sizeof(float)>&>(f)y obtener exactamente la misma salida. ¿Prueba algo?std::arraysatisface los requisitos de ContiguiosContainer (desde C ++ 17) .std::vectortambién satisface los mismos criterios y obviamente no se puede usar aquí. ¿Hay algo que requiera questd::arraymantenga los elementos dentro de la clase (en un campo), evitando que sea un puntero simple a la matriz interna? (como en vector, que también tiene un tamaño, que matriz no requiere tener en un campo)std::arrayefectivamente requiere que almacene los elementos dentro, pero me preocupan los problemas de diseño.