漢なら Cereal ですね!
Cereal で JSON 形式で設定ファイルのロードに使いたくなりますね!
その場合, 設定パラメータを optional に読む機能がほしくなりますね.
cereal::make_optional
みたいなのが提案されているようですが, まだ master には取り込まれていないですね...
そんなわけで, issue の最後のほうにある, exception で囲むやりかたで optional なフィールドを読み込んでみましょう.
こんな感じになりました.
(フィールドは全て NVP(name-value-pair) で読むと仮定)
template <class Archive, class T>
static void Optional(Archive &archive, const std::string &name, T &value) {
try {
archive(cereal::make_nvp(name, value));
} catch (std::exception &e) {
(void)e;
// OK
}
}
// Seralize RenderConfig class.
template <class Archive>
static void LoadRenderConfig(Archive &archive, RenderConfig &m) {
// Optional fields
Optional(archive, "width", m.width);
Optional(archive, "height", m.height);
// Mandatory fields.
archive(cereal::make_nvp("eye", m.eye));
archive(cereal::make_nvp("look_at", m.look_at));
archive(cereal::make_nvp("up", m.up));
archive(cereal::make_nvp("fov", m.fov));
}
問題点
構造が深くなって再帰的にロードする場合, Cereal がより上位のレベルで例外を投げてしまい正しくパースができないことがわかりました.
(たとえば, std::vector<MyClass>
で, MyClass
に std::vector
がある場合, MyClass のパースで例外をキャッチしても, std::vector<MyClass>
のパースで例外が出てしまう)
また, 同様に構造が深い場合だと, 例外を使ってパースをスキップすると Cereal 側でメモリリークするケースがあります.
以下のようなサンプルも提案されていますが, 定義順が固定になります.
したがって, 今の所完全に optional なフィールドを Cereal で読む手段を実現するのは難しいですね... 設定ファイルをロードするなどの用途では, 普通に JSON パーサや XML パーサを使うしかなさそうです.
まとめ
Cereal すばらしい.