内部にポインタや参照を含まない型のオブジェクトであれば、単純なバイト列としてバイナリファイルに書き込むことができそうです。実際には仮想関数を持つ型はダメというようにいくつかのさらに制約があります。昔から単純なバイナリーデータとして書き込めるような型は「C互換型(POD型)」と呼ばれていましたが、最近はトリビアルコピー可能な型であればOKということのようです。
トリビアルコピー可能な型の要件はC++規格のバージョンで微妙にぶれているようです。ただ、実用上はそんなに気にすることはありませんし、<type_traits>で定義されるis_trivially_copyableメタ関数を使って判定してあげればOKです。
今回はそれらを踏まえて、トリビアルコピー可能な型のオブジェクトをストリームに出力する関数を作ってみましょう。
0 1 2 3 4 5 6 7 8 9 10 |
template <typename T, class Traits> requires std::is_trivially_copyable_v<T> bool write_var(T const& var, std::basic_ostream<char, Traits>& ostr) { auto p = std::addressof(var); auto n = sizeof(var); ostr.write(const_cast<char const*>(reinterpret_cast<char const volatile*>(p)), n); return ostr.good(); }こ |
コンセプトを使いましたので、コンパイルするにはC++20以降のコンパイラが必要です。C++11から17までのコンパイラであれば、requiresの行を削除して、代わりに関数内部でstatic_assertを使ってT型がis_trivially_copiableかどうかを判定すればよいでしょう。
なお、いったんバイナリーデータとして保存した内容を復元するのは、同じ処理系であれば問題ありませんが、異なる処理系の場合は十分な注意が必要です。型のサイズはもちろん、境界調整やバイトオーダーなどが絡んでくるからです。