在提升序列化中平展嵌套的命名值对
Flatten nested named value pair in Boost Serialization
在Boost.Serialization中序列化的规范方式是定义一个serialize
(或load
/save
(函数,该函数将对象的值状态转换为一系列更原始的值。如果序列化归档文件需要命名值对,则还需要定义名称。
例如
struct A{
double x; int y; unsigned z;
template<class Ar>
void serialize(Ar& ar, unsigned){
ar
& BOOST_SERIALIZATION_NVP(x)
& BOOST_SERIALIZATION_NVP(y)
& BOOST_SERIALIZATION_NVP(z)
;
}
}
...
A a;
boost::archive::xml_oarchive xoa{ofs};
xoa << BOOST_SERIALIZATION(a);
生成类似于以下内容的结构:
<a>
<x>1.2</x>
<y>2</y>
<z>3</z>
</a>
但是,此语法会引入层次结构,有时不需要该层次结构,例如在使用(普通(继承时,扩展类。
struct B{
double x; int y;
template<class Ar>
void serialize(Ar& ar, unsigned){
ar
& BOOST_SERIALIZATION_NVP(x)
& BOOST_SERIALIZATION_NVP(y)
;
}
};
struct C : B{
unsigned z;
template<class Ar>
void serialize(Ar& ar, unsigned){
B& B_part = (*this);
ar
& BOOST_SERIALIZATION_NVP(B_part) // uses code from base
& BOOST_SERIALIZATION_NVP(z)
;
}
};
...
C c; c.x = 1.2; c.y = 2; c.z = 3;
boost::archive::xml_oarchive xoa{ofs};
xoa << BOOST_SERIALIZATION_NVP(c);
<c>
<B_part>
<x>1.2</x>
<y>2</y>
</B_part>
<z>3</z>
</a>
这有点人为。有没有办法强制档案馆扁平化这个参考?并得到这个:
<c>
<x>1.2</x>
<y>2</y>
<z>3</z>
</a>
当然,我可以将结构重写为
struct C : B{
unsigned z;
template<class Ar>
void serialize(Ar& ar, unsigned){
ar
& BOOST_SERIALIZATION_NVP(x)
& BOOST_SERIALIZATION_NVP(y)
& BOOST_SERIALIZATION_NVP(z)
;
}
};
但是这变得很麻烦,因为我必须在派生类中重复基类中的所有代码。
例如,假设的代码可以是这样的:
void serialize(Ar& ar, unsigned){
B& B_part = (*this);
ar
& BOOST_SERIALIZATION_UNNAMED(B_part) // uses code (and names) from base, does not create a new level
& BOOST_SERIALIZATION_NVP(z)
;
}
这种基类的序列化,而不生成较低的级别,是否在库中考虑过什么?
我知道 Boost.Serialization 仍然执行序列化工作,但是 XML 可以通过这种方式变得更加可读。
Boost.Serialization 有很多关于序列化基类和派生类(用于经典多态继承((https://www.boost.org/doc/libs/1_70_0/libs/serialization/doc/serialization.html#base(的文档,但它似乎没有关于使用继承类进行聚合的文档。
*this 投射到基类的诱惑。这似乎有效,但可能无法调用正确序列化所需的代码。
你是对的,如果基类不是多态的,则不是绝对必要的。这是一个建议。但我坚持这一建议。 最好有一个简单的规则,而不是必须重新考虑每个实例。
我质疑尝试将xml文件"塑造"为某些特定口味和/或外观要求的价值。 这会将C++数据结构耦合以履行其他角色。 如果你真的需要使xml文件"可读"或其他什么,一个更好的方法是使用其他工具(如xslt(来修改/过滤序列化库生成的xml。 这将有效地允许您为程序制作最佳的C++数据结构,同时保留处理 xml 的便利性。
我找到了一种方法,(我不知道它是否只是偶然起作用(。
struct C : B{
unsigned z;
template<class Ar>
void serialize(Ar& ar, unsigned u){
B::serialize(ar, u); // base class serialization
// or boost::serialization::serialize(ar, static_cast<B&>(*this), u);
ar
& BOOST_SERIALIZATION_NVP(y)
& BOOST_SERIALIZATION_NVP(z)
;
}
};
(我之前拒绝了这个解决方案,因为我认为它会生成一个重复的 XML 标头,因为它似乎将一个存档嵌套在另一个存档中,但事实并非如此。
这会将任何其他结构平展到归档中,而不仅仅是基类。此外,boost::serialization::serialize
在设计上不适用于基元类型,因此您永远不会得到"未命名"的叶节点。
这将生成所需的结构并重用基库中的代码:
<c>
<x>1.2</x>
<y>2</y>
<z>3</z>
</c>
注意:这正是手册在序列化派生类时不要做的事情,https://www.boost.org/doc/libs/1_70_0/libs/serialization/doc/serialization.html#base
抵制将
*this
投射到基类的诱惑。这似乎有效,但可能无法调用正确序列化所需的代码。
但我认为他指的是(反(多态序列化,从派生实例中保存并在基(指针(中加载实例。
无论如何,这种用法在这里永远不会起作用,因为从B
值序列化的东西反序列化为C
值,或者相反,arround 将是值语义哲学中的逻辑错误(以及运行时错误,因为它们具有不同数量的成员(。
- 嵌套在类中时无法设置成员数据
- 无法访问嵌套类.类的使用无效
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- 如何在C++中初始化嵌套类中的2个memeber
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 在C++中搜索嵌套多映射值
- 在C++中将矢量转换为嵌套地图
- C++嵌套if语句,基本货币交换
- 在nlohmann json中,如何将嵌套对象的数组转换为嵌套结构的向量
- 嵌套的匿名命名空间
- 了解嵌套循环打印星号图案
- 如何使用boost::具有嵌套结构和最小代码更改的序列化
- 嵌套for循环C++的问题(初学者)
- 从嵌套在std::映射中的std::列表中删除元素的最佳方式
- 用C#中的并集模拟C++嵌套结构
- 部分专业化和嵌套模板
- 嵌套While循环不起作用(C++问题)
- C++-模板嵌套类的引用初始化无效
- 如何在嵌套类中正确使用友元声明?
- 按升序对数组进行排序嵌套循环问题