web-dev-qa-db-ja.com

std :: arrayを使用したstd :: bit_cast

彼の最近の講演で 「Type C punning in modern C++」 Timur Doumler said そのstd::bit_castを使用してfloatunsigned char[4]にビットキャストすることはできません関数から配列を返すことはできません。 std::memcpyを使用するか、reinterpret_cast<unsigned char*>(&f)[i]のようなものが明確になるC++ 23(またはそれ以降)まで待つ必要があります。

C++ 20では、std::arraystd::bit_castとともに使用できますか、

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

cスタイルの配列の代わりにfloat

14
Evg

はい、これはすべての主要なコンパイラで動作します。標準を見てもわかる限り、移植性があり、動作することが保証されています。

まず、std::array<unsigned char, sizeof(float)>は、集合体であることが保証されています( https://eel.is/c++draft/array#overview-2 )。これは、内部にsizeof(float)数のcharsを正確に保持することを示しています(通常、char[]として)。標準ではこの特定の実装は必須ではありませんが、要素は隣接している必要があります)。追加の非静的メンバーを持つことはできません。

したがって、簡単にコピーでき、そのサイズもfloatのサイズと一致します。

これらの2つのプロパティを使用すると、それらの間でbit_castを実行できます。

15
Timur Doumler

配置とパディングの問題を考慮していないため、受け入れられた答えは正しくありません。

[array]/1- ごと:

ヘッダー_<array>_は、オブジェクトの固定サイズのシーケンスを格納するためのクラステンプレートを定義します。配列は連続したコンテナです。 _array<T, N>_のインスタンスは、タイプNT要素を格納するため、size() == Nは不変です。

配列は、型をNに変換できるT要素まででリスト初期化できる集約です。

配列は、コンテナーおよびリバーシブルコンテナー(_[container.requirements]_)のすべての要件を満たしていますが、デフォルトで作成された配列オブジェクトは空ではなく、スワップは複雑ではありません。配列は、シーケンスコンテナーの要件のいくつかを満たしています。ここでは、これらの表のいずれにも記載されていない配列の操作と、追加のセマンティック情報がある操作についてのみ説明します。

標準では、実際には_std::array_が_T[N]_型のパブリックデータメンバーを1つだけ持つ必要はないため、理論的にはsizeof(To) != sizeof(From)または_is_­trivially_­copyable_­v<To>_が可能です。

これが実際に機能しない場合は、私は驚きます。

6
L. F.

はい。

_std::bit_cast_の動作を説明する paper とその 提案された実装 によると、両方のタイプが同じサイズであり、簡単にコピーできる限り、キャストは成功した。

_std::bit_cast_の簡略化された実装は、次のようになります。

_template <class Dest, class Source>
inline Dest bit_cast(Source const &source) {
    static_assert(sizeof(Dest) == sizeof(Source));
    static_assert(std::is_trivially_copyable<Dest>::value);
    static_assert(std::is_trivially_copyable<Source>::value);

    Dest dest;
    std::memcpy(&dest, &source, sizeof(dest));
    return dest;
}
_

Float(4バイト)およびsize_of(float)を含む_unsigned char_の配列は、これらすべてのアサートを尊重するため、基礎となる_std::memcpy_が実行されます。したがって、結果の配列の各要素は、floatの1つの連続したバイトになります。

この動作を証明するために、コンパイラエクスプローラーで小さな例を書いて、ここで試すことができます: https://godbolt.org/z/4G21zS 。浮動小数点数5.0は、その浮動小数点数の16進表現 ビッグエンディアン に対応するバイトの配列(_Ox40a00000_)として適切に格納されます。

2
Manuel Gil