让我首先说明为什么谷物输出的样式比您可能想要的更冗长。谷物是为与任意序列化档案一起工作而编写的,并采取了一种满足所有这些档案的中间方法。想象一下,键类型比字符串或算术类型更复杂——我们如何以简单的"key" : "value" 方式对其进行序列化?
另请注意,谷物预计会成为它读取的任何数据的祖先。
话虽如此,谷物完全可以满足您的需求,但存在一些障碍:
要克服的最大障碍是,您所需的输入序列化了 JSON 对象而不是 JSON 数组中一些未知数量的名称-值对。谷物被设计为在处理可以容纳可变数量元素的容器时使用 JSON 数组,因为考虑到它使用的底层 rapidjson 解析器,这是最有意义的。
其次,谷物目前不希望名称-值-对中的名称实际加载到内存中 - 它只是将它们用作组织工具。
如此漫无边际,这里有一个完全可行的解决方案(可以变得更优雅),只需对谷物进行极少的更改(这实际上使用了 slated for cereal 1.1 的更改,当前版本是 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 档案。在 XML 存档中添加一个类似的 getNodeName() 可能也会让它在那里工作,但显然这对二进制存档没有意义。
为了使这个干净,你想把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"
}
}