让我首先解释为什么谷物会输出比您想要的更冗长的样式。谷物被编写为可与任意序列化档案一起使用,并采取中间立场来满足所有这些档案。想象一下键类型比字符串或算术类型完全复杂 - 我们如何以简单的方式序列化它"key" : "value"
way?
另请注意,谷物预计将成为其读入的任何数据的祖先。
话虽如此,您想要的谷物食品完全可以实现,但存在一些障碍:
需要克服的最大障碍是您所需的输入在 JSON 对象而不是 JSON 数组内序列化一些未知数量的名称-值对。谷物被设计为在处理可以容纳可变数量元素的容器时使用 JSON 数组,因为考虑到它使用的底层rapidjson解析器,这是最有意义的。
其次,谷物目前并不期望名称-值对中的名称实际加载到内存中 - 它只是将它们用作组织工具。
杂乱无章地完成了,这里有一个完全有效的解决方案(可以做得更优雅),只需对谷物进行很少的更改即可解决您的问题(实际上,这使用了以下更改)预计用于谷物 1.1 https://github.com/USCiLab/cereal/pull/66,当前版本为1.0):
将此功能添加到JSONInputArchive
:
//! Retrieves the current node name
/*! @return nullptr if no name exists */
const char * getNodeName() const
{
return itsIteratorStack.back().name();
}
然后,您可以编写序列化的专门化std::map
(或无序,无论您喜欢哪种)对于一对字符串。确保将其放入cereal
命名空间,以便编译器可以找到它。此代码应该存在于您自己的文件中的某个位置:
namespace cereal
{
//! Saving for std::map<std::string, std::string>
template <class Archive, class C, class A> inline
void save( Archive & ar, std::map<std::string, std::string, C, A> const & map )
{
for( const auto & i : map )
ar( cereal::make_nvp( i.first, i.second ) );
}
//! Loading for std::map<std::string, std::string>
template <class Archive, class C, class A> inline
void load( Archive & ar, std::map<std::string, std::string, C, A> & map )
{
map.clear();
auto hint = map.begin();
while( true )
{
const auto namePtr = ar.getNodeName();
if( !namePtr )
break;
std::string key = namePtr;
std::string value; ar( value );
hint = map.emplace_hint( hint, std::move( key ), std::move( value ) );
}
}
} // namespace cereal
这不是最优雅的解决方案,但效果很好。我将所有内容都保留为通用模板,但考虑到所做的更改,我上面写的内容仅适用于 JSON 存档。添加类似的getNodeName()
到 XML 存档可能也会让它在那里工作,但显然这对于二进制存档没有意义。
为了使它干净,你需要把enable_if
围绕它所使用的档案。您还需要修改谷物中的 JSON 档案以使用可变大小的 JSON 对象。要了解如何执行此操作,请查看谷物食品在获取时如何在存档中设置状态SizeTag
序列化。基本上,您必须使存档不打开数组,而是打开一个对象,然后创建您自己的版本loadSize()
这会看到物体有多大(这将是一个Member
用rapidjson的说法)。
要查看上述内容的实际效果,请运行以下代码:
int main()
{
std::stringstream ss;
{
cereal::JSONOutputArchive ar(ss);
std::map<std::string, std::string> filter = {{"type", "sensor"}, {"status", "critical"}};
ar( CEREAL_NVP(filter) );
}
std::cout << ss.str() << std::endl;
{
cereal::JSONInputArchive ar(ss);
cereal::JSONOutputArchive ar2(std::cout);
std::map<std::string, std::string> filter;
ar( CEREAL_NVP(filter) );
ar2( CEREAL_NVP(filter) );
}
std::cout << std::endl;
return 0;
}
你会得到:
{
"filter": {
"status": "critical",
"type": "sensor"
}
}
{
"filter": {
"status": "critical",
"type": "sensor"
}
}