std :: bit_cast与std :: array

Evg*_*Evg 14 c++ type-punning c++20

Timur Doumler 在他最近的演讲“现代C ++中的类型修剪”中,由于不能从函数返回C样式的数组,std::bit_cast因此不能用于将a进行位强制float转换unsigned char[4]。我们应该使用std::memcpy或等到C ++ 23(或更高版本)后,类似的东西reinterpret_cast<unsigned char*>(&f)[i]才能被很好地定义。

在C ++ 20中,我们可以在中std::array使用std::bit_cast

float f = /* some value */;
auto bits = std::bit_cast<std::array<unsigned char, sizeof(float)>>(f);
Run Code Online (Sandbox Code Playgroud)

而不是C样式的数组来获取float?的字节?

Tim*_*ler 15

是的,这适用于所有主要的编译器,据我观察标准可以得知,它是可移植的,并且可以正常工作。

首先,std::array<unsigned char, sizeof(float)>保证是一个聚合(https://eel.is/c++draft/array#overview-2)。由此可见,它内部恰好包含sizeof(float)多个chars(通常以a表示char[],尽管从原则上讲,该标准并未强制要求该特定实现-但它确实说元素必须是连续的),并且不能具有任何其他非静态成员。

因此,它是可复制的,并且其大小也与之匹配float

这两个属性允许您bit_cast在它们之间。

  • 注意`struct X {unsigned char elems [5]; };`满足您所引用的规则。当然,可以使用最多4个元素对列表进行初始化。也可以使用5个元素对列表进行初始化。我认为没有任何标准库实现者会讨厌这样做的人,但是我认为这在技术上是一致的。 (3认同)
  • @Timur“最多”并不意味着“不超过”。隐含意义“ P-&gt; Q”并不暗示“!P”的情况。 (2认同)
  • 即使聚合只包含一个恰好包含 4 个元素的数组,也不能保证“array”本身不会有填充。它的实现可能没有填充(任何有填充的实现都应该被视为功能失调),但不能保证“array”本身不会。 (2认同)

L. *_* F. 6

接受的答案是错误的,因为它没有考虑对齐和填充问题。

[array] / 1-3

标头<array>定义用于存储固定大小的对象序列的类模板。数组是一个连续的容器。array<T, N>存储N类型为的元素的实例T,因此size() == N是不变的。

数组是一个聚合,最多可以将N 其类型转换为的元素进行列表初始化T

数组满足容器和可逆容器([container.requirements])的所有要求,除了默认构造的数组对象不为空并且交换不具有恒定的复杂性。数组满足序列容器的某些要求。在此仅提供对这些表之一中未描述的对数组的操作以及存在其他语义信息的操作的描述。

该标准实际上不需要std::array拥有一个类型的公共数据成员T[N],因此从理论上讲,可能是sizeof(To) != sizeof(From)is_­trivially_­copyable_­v<To>

但是,如果这在实践中不起作用,我将感到惊讶。