有没有办法使用 Cereal / C++ 为 std::map 指定更简单的 JSON(反)序列化?

2024-04-16

我正在从事的项目是一个管理大量自定义硬件设备的 C++ 应用程序。该应用程序有一个供客户端使用的套接字/端口接口(如 GUI)。每种设备类型都有自己定义良好的 JSON 模式,我们可以使用 Cereal 来序列化这些模式。

但应用程序还需要解析来自客户端的入站 JSON 请求。请求的一部分指定设备过滤器参数,大致类似于 SQL“WHERE”子句,其中所有表达式都通过 AND 组合在一起。例如。:

"filter": { "type": "sensor", "status": "critical" }

这表明客户端想要在每个具有“关键”状态的“传感器”设备上执行操作。从表面上看,过滤器参数的 C++ 实现似乎是一个 std::map。但是当我们尝试使用 Cereal 来反序列化对象时,它失败了。当我们序列化硬编码的过滤器映射时,它看起来像这样:

"filter": [
   { "key": "type", "value": "sensor" },
   { "key": "status", "value": "critical" }
]

现在我可以理解为什么 Cereal 支持这种详细的映射序列化了。毕竟,映射的键可以是非字符串类型。但在这种情况下关键is一个字符串。

我并不热衷于重写我们的接口规范并让我们的客户生成明显非惯用的 JSON 只是为了满足 Cereal。我是谷物的新手,我们陷入了这一点。有没有办法告诉 Cereal 将此过滤器解析为 std::map ?或者也许我问错了。是否还有其他我们应该反序列化到的 stl 容器?


让我首先解释为什么谷物会输出比您想要的更冗长的样式。谷物被编写为可与任意序列化档案一起使用,并采取中间立场来满足所有这些档案。想象一下键类型比字符串或算术类型完全复杂 - 我们如何以简单的方式序列化它"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"
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有没有办法使用 Cereal / C++ 为 std::map 指定更简单的 JSON(反)序列化? 的相关文章

  • 调试Windows服务

    Scenario 我有一个用 C 编写的 Windows 服务 我已经阅读了所有关于如何调试它的谷歌线程 但我仍然无法让它工作 我已经运行 PathTo NetFramework InstallUtil exe C MyService ex
  • 在 C# 中,为什么从列表创建 HashSet 比从 HashSet 开始更快?

    我有一个方法 它采用上限 并返回达到该限制的素数列表 public static List
  • 为什么我不能声明对可变对象的引用? (“引用不能声明为可变的”)

    假设我们有一个test cpp如下 class A class B private A mutable a 汇编 gt gcc test cpp test cpp 6 20 error reference a cannot be decla
  • 序列化/反序列化 LinkedHashMap (android) java

    所以我想将 LinkedHashMap 传递给意图 SEND THE MAP Intent singlechannel new Intent getBaseContext singlechannel class singlechannel
  • 在 Windows 上实现堆栈跟踪 [关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我正在为我正在编写的游戏实现一个崩溃报告工具 并且我想为该报告提供 相当 详细的本机堆栈跟踪 我已经在 GNU Linux 上实现
  • 如果文本框不为空,如何添加并显示工具提示文本框 WPF

    需要显示提示 其中包含文本字段中的数据 文本框有数据时出现提示 只需使用绑定到 ToolTipService 附加属性即可 XAML
  • M1 MacBook Pro 和 cmake 的编译错误

    我刚刚拿到了新的 M1 MacBook Pro 正在尝试编译大学工作所需的代码库 以下是我已采取的步骤 我使用 Rosetta 将终端设置为始终打开 安装的自制程序using bin bash c curl fsSL https raw g
  • 如何反序列化数组 google-gson 内的数组

    我有这样的 JSON Answers Locale Ru Name Name1 Locale En Name Name2 Locale Ru Name Name3 Locale En Name Name4 正如你所看到的 我的数组里面有数组
  • C# - 获取 GPU 的总使用百分比

    我正在向我的程序添加一些新功能 这些功能当前通过串行连接将 CPU 使用情况和 RAM 使用情况发送到 Arduino 请参阅this https create arduino cc projecthub thesahilsaluja cp
  • 如何使用 json 谷歌翻译 api?

    我正在尝试使用来自 python 的 google 翻译和 utf 8 文本 如何调用json api 他们有一个将其嵌入 html 的文档 但我在任何地方都找不到合适的 API 或 wsdl 谢谢 拉斐尔 这是最终对我有用的代码 使用没有
  • 接收UDP数据包

    假设我的程序通过网络 UDP 发送 1000 字节 它是否保证接收方将 一批 接收 1000 个字节 或者他可能需要执行多次 读取 直到收到完整的消息 如果后者为真 我如何确保同一消息的数据包顺序不会 混淆 按顺序 或者协议可能保证这一点
  • 移动数组中的元素

    我需要一点帮助 我想将数组中的元素向上移动一个元素 以便新位置 1 包含位置 1 中的旧值 new 2 包含 old 1 依此类推 旧的最后一个值被丢弃 第一个位置的新值是我每秒给出的新值 我使用大小为 10 的数组 uint32 t TE
  • 如何使用最小起订量模拟 Controller.User

    我有几个 ActionMethods 查询 Controller User 的角色 如下所示 bool isAdmin User IsInRole admin 在这种情况下可以方便地行事 我开始使用这样的代码对这些方法进行测试 TestMe
  • 将对象转换为泛型类型

    我已经有一段时间没有睡觉了 所以这可能比我想象的要容易 我有一个通用类或多或少是这样的 public class Reference
  • 位运算符,而不是在分支中使用异或

    问完后这个问题 https stackoverflow com questions 22336015 why use xor with a literal instead of inversion bitwise not 我收到了 Ando
  • Azure:MissingRegistrationForLocation:未在位置“YYYY”中为资源类型“XXXX”注册订阅

    这最初是作为未找到订阅 https stackoverflow com questions 35071797 subscriptionnotfound the subscription resourcegroups could not be
  • 显式调用静态构造函数

    我想为下面的课程编写单元测试 如果名称不是 MyEntity 则 mgr 应为空 消极的单元测试 使用 Manager 私有访问器 我想将名称更改为 Test 以便 mgr 应该为空 然后会验证 mgr 值 为了实现这一点 我想显式调用静态
  • LINQ 表达式树 Any() 位于Where() 内

    我正在尝试生成以下 LINQ 查询 Query the database for all AdAccountAlerts that haven t had notifications sent out Then get the entity
  • MDI 窗体中的子窗口对接

    我有一个 MDI 表单和其中的一些子表单 我将子窗体停靠到 MDI 窗口的不同区域 但是当任何子窗体失去焦点时 其他停靠的窗体将重新排列 由于混乱 我准备了一组图像来展示该行为 Image1 单击任何窗口之前 Image2 点击窗口2后 问
  • Phong 着色问题

    我正在根据以下内容编写着色器冯模型 http en wikipedia org wiki Phong reflection model 我正在尝试实现这个方程 其中 n 是法线 l 是光线方向 v 是相机方向 r 是光反射 维基百科文章中更

随机推荐