6

次のような C++ のクラスがあるとします。

struct Point {
    int x, y, z;
};

Cereal を使用して、その構造体を JSON にシリアライズしたいと考えています。そこで、次のようなシリアル化関数を追加しました。

struct Point {
    int x, y, z;
    template<class Archive>
    void serialize(Archive& ar) {
        ar(CEREAL_NVP(x),
           CEREAL_NVP(y),
           CEREAL_NVP(z));
    }
};

Point が別のオブジェクトのメンバーまたは配列の要素である場合、これは正常に機能します。しかし、Point を JSON ファイル全体の主要なオブジェクトにしたい場合、正しく機能しません。たとえば、次のコードを使用します。

Point p { 1, 2, 3 };
cereal::JSONOutputArchive ar(std::cout);
ar(p);

次の出力が得られます。

{
    "value0": {
        "x": 1,
        "y": 2,
        "z": 3
    }
}

"value0"次のように、キーを削除し、ファイル全体を占めるようにオブジェクトを昇格させたいと思います。

{
    "x": 1,
    "y": 2,
    "z": 3
}

私がそれを行うことができる唯一の方法は、基本的にシリアライゼーション関数を再実装し、キー名を手動で追加することです。

Point p {1, 2, 3};
cereal::JSONOutputArchive ar(std::cout);
ar(cereal::make_nvp("x", p.x),
   cereal::make_nvp("y", p.y),
   cereal::make_nvp("z", p.z));

クラスに既に実装したシリアル化機能を利用してそれを行う方法はありますか?

4

3 に答える 3

2

シリアル化するクラスにメソッドがあることを事前に知っている場合、ベンジャミンの答えは完璧なソリューションですserialize()。Cereal は in-class/out-of-class serialize()、 split load()/save()、明示的なバージョン管理をサポートしているため。いつもそうであるとは限りません。Cereal の内部クラスcereal::InputArchivecereal::OutputArchiveクラスの両方に、コンパイル時に使用する適切なシリアル化メソッドを検出するための SFINAE テンプレート メソッドが多数あります。そこにある型特性を使用して、独自のテンプレート スイッチをロールすることができます。

template< typename Class, typename Archive,
          typename std::enable_if< cereal::traits::has_member_serialize<Class, Archive>::value>::type* = nullptr>
inline static void serializeHelper(Class& cl, Archive& ar)
{
    cl.serialize(ar);
}

template< typename Class, typename Archive,
          typename std::enable_if< cereal::traits::has_member_save<Class, Archive>::value>::type* = nullptr>
inline static void serializeHelper(Class& cl, Archive& ar)
{
    cl.save(ar);
}

// More version could follow for remaining serialization types (external, versioned...)

template< typename Class, typename Archive,
          typename std::enable_if< cereal::traits::has_member_serialize<Class, Archive>::value>::type* = nullptr>
inline static void deserializeHelper(Class& cl, Archive& ar)
{
    cl.serialize(ar);
}

template< typename Class, typename Archive,
          typename std::enable_if< cereal::traits::has_member_load<Class, Archive>::value>::type* = nullptr>
inline static void deserializeHelper(Class& cl, Archive& ar)
{
    cl.load(ar);
}

// More version could follow for remaining deserialization types (external, versioned...)

を呼び出すと、Cereal が内部で行うのと同じ方法で、serializeHelper(p, ar);によって提供されるシリアル化方法が自動的に選択されます。Point

于 2016-05-18T10:11:23.443 に答える
1

選択したアーカイブからのものが代わりに選択されないように、独自のタイプの関数epilogueと関数を no-opsに定義する必要があります。prologue

#include <cereal/archives/json.hpp>
#include <iostream>

struct Point {
    int x, y, z;
    template<class Archive>
    void serialize(Archive& ar) {
        ar(CEREAL_NVP(x),
           CEREAL_NVP(y),
           CEREAL_NVP(z));
    }
};

void epilogue(cereal::JSONOutputArchive&, const Point &){}
void prologue(cereal::JSONOutputArchive&, const Point &){}

int main()
{
    Point p { 1, 2, 3 };
    cereal::JSONOutputArchive ar(std::cout);
    ar(p); 

    return 0;
}
于 2020-05-01T03:49:17.177 に答える