概要
先日投稿されていた 「C++のcerealのシリアライズが快適すぎるやばい」 を読んでこれは良いと思い、早速今日からお仕事でも使おうとはじめに確認した事や少々まはった事をまとめておきます。
確認した事
1. std::uint64_t
を JSON でシリアライズするとどうなるか?
答え: C++er の期待通りにシリアライズされる。心配ない。
#include <cereal/cereal.hpp>
#include <cereal/archives/json.hpp>
#include <limits>
#include <cstint>
#include <iostream>
auto main() -> int
{
cereal::JSONOutputArchive( std::cout )( std::numeric_limits< std::uint64_t >::max() );
}
{
"value0": 18446744073709551615
}
だそく: 以前JSONを扱いたい状況で picojson
を使おうとサンプルも書いて提案したら「 64-bit 値を数値で扱えないみたいなんですがー」と言われ採用できない事がありました。picojson
だと PICOJSON_USE_INT64
しても std::uint64_t
はサポートされなかった悲しみの思い出。
2. enum class
を手間なくシリアライズできるか?
答え: 全自動で std::underlying_type
を見てシリアライズしてくれる。楽々。
#include <cereal/cereal.hpp>
#include <cereal/archives/json.hpp>
#include <cstint>
#include <iostream>
enum class pon_type
: std::uint8_t
{ none
, ajipon
, yuzupon
, sudachipon
};
auto main() -> int
{
cereal::JSONOutputArchive( std::cout )( pon_type::yuzupon );
}
{
"value0": 2
}{
3. Binary シリアライズでエンディアンはどうなるか?
答え: Binary 系 API を使うとエンディアンでアプリが爆発するかもしれないけれど、そんなユースケースには PortableBinary 系 API があるから大丈夫だよ。
Binary 系 API の場合
#include <cereal/cereal.hpp>
#include <cereal/archives/json.hpp>
#include <cstint>
#include <fstream>
auto main() -> int
{
std::ofstream f( "a.bin", std::ios::binary );
if ( f.is_open() )
( cereal::BinaryOutputArchive( f ) )( static_cast< std::uint16_t >( 0x1234 ) );
}
intel Core i7 でビルドし実行した結果を od -t x1 a.bin
で眺めると:
0000000 34 12
0000002
PortableBinary 系 API の場合
#include <cereal/cereal.hpp>
#include <cereal/archives/json.hpp>
#include <cstint>
#include <fstream>
auto main() -> int
{
std::ofstream f( "a.bin", std::ios::binary );
if ( f.is_open() )
( cereal::BinaryOutputArchive( f ) )( static_cast< std::uint16_t >( 0x1234 ) );
}
intel Core i7 でビルドし実行した結果を od -t x1 a.bin
で眺めると:
0000000 01 34 12
0000003
エンディアンのフラグが先頭に 1 byte くっつく。
はまった事
1. std::map
std::unordered_map
試そ -> error
状況: とりあえず基本的なシリアライザーの動作を確認しよう、 std::uint64_t 、 enum class 、 std::vector 、 std::unordered_map ... compile error !!
#include <cereal/cereal.hpp>
#include <cereal/unordered_map.hpp>
#include <cereal/archives/json.hpp>
#include <unordered_map>
#include <string>
#include <iostream>
#include <cstint>
auto main() -> int
{
std::unordered_map< std::string, std::uint16_t > data
{ { "alice" , 0x1122 }
, { "bob" , 0x3344 }
, { "charlie", 0x5566 }
};
cereal::JSONOutputArchive( std::cout )( data );
}
翻訳時エラー:
cereal/include/cereal/cereal.hpp:448:9: error: static assertion failed: cereal could not find any output serialization functions for the provided type and archive combination.
Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these).
Serialize functions generally have the following signature:
template<class Archive>
void serialize(Archive & ar)
{
ar( member1, member2, member3 );
}
static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value != 0,
^
答え: #include <cereal/types/string.hpp>
が抜けてた (ノω・)テヘ
しばらく cereal が内蔵で対応してるはずだし types/unordered_map も読んでるしなんでやろ?w? などと間抜けな状況を経験した。
ちなみに、このエラー、本来はユーザー定義のシリアライズを行おうとした時にユーザーへ親切丁寧に問題を知らせてくれるもの。C++にしては気配りのよく効いたいい子ですね・w・b
所感
とても扱い易く楽に使えて嬉しい C++er に愛されそうなシリアライザーライブラリーですね。STL対応もお馴染みのコンテナーやコンテナーアダプター群はもちろん、 std::valarray
std::complex
std::tuple
std::bitset
などにまで対応が広がっていて多くの状況で手間なく安心して利用できます。さっそく、今日の午後のお仕事から私も実用して参りましょう( ・`ω・´)