如何序列化json对象,而不使用麦片将其封装在子对象中
How to serialize a json object without enclosing it in a sub-object using Cereal
假设我在C++中有一个类,如下所示:
struct Point {
int x, y, z;
};
我想使用谷物将该结构序列化为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成为整个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));
有没有任何方法可以利用我已经为类实现的序列化函数来实现它?
好吧,想通了。非常简单,只需要直接从对象调用序列化函数,传递归档文件,而不是将对象传递到归档文件。
Point p {1, 2, 3};
cereal::JSONOutputArchive ar(std::cout);
p.serialize(ar);
Benjamin的答案是完美的解决方案,如果您事先知道要序列化的类有一个serialize()
方法。由于麦片支持类内/类外serialize()
,拆分load()/save()
,显式版本控制;但情况并非总是如此。Cereal的内部cereal::InputArchive
和cereal::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...)
调用serializeHelper(p, ar);
会自动选择Point
提供的序列化方法,与麦片内部的方法相同。
您需要将自己类型的epilogue
和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;
}
相关文章:
- 将 RTOS 队列对象封装在仅具有静态分配的 IQueue 自定义接口中
- 从封装在对象中的函数 C++ 返回时为空的列表
- 当要访问的对象被多次封装时,如何正确使用setter
- 是否有更好的方法来封装成员对象可以访问的共享存储池?
- 封装和消息对象
- 期望在模拟对象上调用了某个方法.它会破坏封装吗?
- 封装与大型C 对象中的指针返回
- 在 C++ 中将一个类的多个对象封装在另一个类中
- 当一个对象的死亡使另一个对象生病时,如何保持封装
- 在类中封装游戏对象
- 如何在haskell中封装对象构造函数和析构函数
- 带有构造函数的c++对象将值放入封装的对象中
- 如何序列化json对象,而不使用麦片将其封装在子对象中
- 将可释放对象封装到智能指针中
- 封装迭代器提供的对象
- 在Node插件中将c++对象封装为v8对象
- 对象切片是否会破坏封装
- 在使用QOpenGLFunctions时将OpenGL功能封装在c++对象中
- 我的GLSL着色器对象/包装器是否应该封装加载/设置VertexArrayObject
- 当关联的Javascript对象在V8中被垃圾回收时,如何释放封装的C++对象