前提・実現したいこと
c++20で標準ライブラリに実装されるstd::bit_cast
について
std bit_cast - cpprefjp
std::bit_cast - cppreference.com
の説明を読んでいたところ、cpprefjpでは
そのような目的にはstd::aligned_storageとstd::memcpy()を組み合わせて使用することになるが、
となっていますが、cppreferenceにはc++17以前のコードとして
c++
1template <class To, class From> 2typename std::enable_if< 3 (sizeof(To) == sizeof(From)) && 4 std::is_trivially_copyable<From>::value && 5 std::is_trivial<To>::value, 6 // この実装は To がトリビアルにデフォルト構築可能であることを要求します。 7 To>::type 8// constexpr のサポートはコンパイラマジックが必要です。 9bit_cast(const From &src) noexcept 10{ 11 To dst; 12 std::memcpy(&dst, &src, sizeof(To)); 13 return dst; 14}
が掲載されていました。こちらのコードにはstd::aligned_storage
が使われていないようです。
教えていただきたいこと
std::aligned_storage
を用いる方法とそうでない方法で、どのような違いがあるか- c++17以前で
std::bit_cast
のようなtype punningを行うとき、変換前後の型が整数型、浮動小数点型に限られる場合、constexprにこれを行う方法があるか
よろしくおねがいします
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
ベストアンサー
std::aligned_storage
を用いる方法とそうでない方法で、どのような違いがあるか
変換先型To
に対する「デフォルトコンストラクタの要求」有無が異なると思います。より汎用性の高い実装では、デフォルトコンストラクタを必要としない std::aligned_storage
が必要となります。
cpprefjpの文言は、提案文書 P0476R2 からの引用・翻訳と思われます。原文後半にはaligned_storage
が必要となる理由への言及があります(太字)。
Attuned developers use
aligned_storage
withmemcpy
, avoiding alignment pitfalls and allowing them to bit-cast non-default-constructible types.
提案者自身による実装例 jfbastien/bit_cast も、下記実装になっています(引用に際して一部簡略化しました):
C++
1template<typename To, typename From> 2inline constexpr To bit_cast(const From& from) noexcept { 3 typename std::aligned_storage<sizeof(To), alignof(To)>::type storage; 4 std::memcpy(&storage, &from, sizeof(To)); 5 return reinterpret_cast<To&>(storage); 6 // More common implementation: 7 // std::remove_const_t<To> to{}; 8 // std::memcpy(&to, &from, sizeof(To)); 9 // return to; 10}
c++17以前でstd::bit_castのようなtype punningを行うとき、変換前後の型が整数型、浮動小数点型に限られる場合、constexprにこれを行う方法があるか
C++17標準仕様の範囲内では不可能と思われます。だからこそ std::bit_cast
関数が追加されたはずです。C++20でも結局はコンパイラによる特殊サポートが必須となります。(std::bit_cast
は"コンパイラマジック”関数として実現されます)
提案文書 P0476R2 §1. Backgroundより引用:
Furthermore, it is currently impossible to implement a
constexpr
bit-cast function, asmemcpy
itself isn'tconstexpr
. Marking the proposed function asconstexpr
doesn't require or preventmemcpy
from becomingconstexpr
, but requires compiler support. This leaves implementations free to use their own internal solution (e.g. LLVM has a bitcast opcode).
投稿2019/04/12 06:59
編集2019/04/12 07:03総合スコア6191
0
こんにちは。
ごめんなさい。回答にはなりませんでした。
1.std::aligned_storageを用いる方法とそうでない方法で、どのような違いがあるか
cppreference のようなコードの場合、TO の領域を確保した時に TO のコンストラクタが走ると思います。
その上で、データを上書きするのでかなり危険な感じがします。
TO は std::is_trivially_copyable が true ですが、trivially_copyableな型でもコンストラクタを持てないわけではなさそうです。
しかし、上記ページにはis_trivially_copyableであれば std::memcpy 可能とも書かれていますね。例えば、副作用があるようなデフォルト・コンストラクタを持っている型へ std::memcpy ってリスキーな印象を受けます。
更にしかし、規格上それがプログラマの責任とされているのならば、cppreference のコードも規格内ということになりそうです。
そして、そのようなコンストラクタの発動を恐れる場合は、アライメントが取れているメモリ領域を確保してそこへ std:memcpy すればよいと思いますので、このような実装をする場合には、std::aligned_storage を使うとスマートにかけそうです。
この辺は、ライブラリの実装者の考え方に依存しそうです。(なんとなくgccは前者、msvcは後者をとりそうな。偏見かも?)
2.c++17以前でstd::bit_castのようなtype punningを行うとき、変換前後の型が整数型、浮動小数点型に限られる場合、constexprにこれを行う方法があるか
ここの A Proposal to Add Constexpr Modifiers to Functions in <algorithm> and <cstring> Headers
を見るとこの提案がC++17に採用されていなかった場合、compiler intrinsics を使わないと無理そうですね。
投稿2019/04/12 03:41
編集2019/04/12 03:43総合スコア23272
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/04/12 04:12
2019/04/12 04:35
2019/04/12 05:37
2019/04/12 05:38
2019/04/12 05:51
2019/04/12 07:15
2019/04/12 07:30 編集
2019/04/12 07:55
2019/04/12 08:26 編集
2019/04/12 09:15
2019/04/12 10:13
2019/04/12 10:49 編集
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/04/12 12:44