首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用Cereal序列化json对象而不将其封装在子对象中。

如何使用Cereal序列化json对象而不将其封装在子对象中。
EN

Stack Overflow用户
提问于 2015-11-15 22:54:30
回答 3查看 3.5K关注 0票数 6

假设我在C++中有一个类,如下所示:

代码语言:javascript
复制
struct Point {
    int x, y, z;
};

我想使用Cereal将该结构序列化为JSON。所以我添加了一个序列化函数,如下所示:

代码语言:javascript
复制
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文件的主要对象,它就不能正常工作。例如,使用以下代码:

代码语言:javascript
复制
Point p { 1, 2, 3 };
cereal::JSONOutputArchive ar(std::cout);
ar(p);

我得到以下输出:

代码语言:javascript
复制
{
    "value0": {
        "x": 1,
        "y": 2,
        "z": 3
    }
}

我想移除"value0"键并提升对象以占据整个文件,如下所示:

代码语言:javascript
复制
{
    "x": 1,
    "y": 2,
    "z": 3
}

唯一能做到这一点的方法是,基本上重新实现序列化函数,手动添加键名。

代码语言:javascript
复制
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));

有任何方法可以利用我已经为类实现的序列化函数来完成它吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-11-15 23:06:57

好吧,想清楚了。非常简单,只需要直接从对象调用序列化函数,传递存档,而不是将对象传递给存档。

代码语言:javascript
复制
Point p {1, 2, 3};
cereal::JSONOutputArchive ar(std::cout);
p.serialize(ar);
票数 9
EN

Stack Overflow用户

发布于 2016-05-18 10:11:23

如果您预先知道要序列化的类有一个serialize()方法,则Benjamin的回答是完美的解决方案。由于Cereal支持类内/类外的serialize()、拆分load()/save()、显式版本控制,所以情况并不总是如此。谷物的内部cereal::InputArchivecereal::OutputArchive类都有大量的SFINAE模板方法来检测编译期间要使用的正确的序列化方法。那里的类型特征可以用来滚动我们自己的模板开关:

代码语言:javascript
复制
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...)

调用serializeHelper(p, ar);将自动选择Point提供的序列化方法,就像Cereal在内部所做的那样。

票数 2
EN

Stack Overflow用户

发布于 2020-05-01 03:49:17

您需要为您自己的类型定义epilogueprologue函数,以便不选择所选存档中的函数。

代码语言:javascript
复制
#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;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33726072

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档