惊喜!C++ 现代化json库nlohmann更高效的使用方式

背景

nlohmann 这个库其实早在2019年项目中已经开始使用了,没有问题,这些库一般都不会进行升级。 最近在新的项目中也需要用Json解析,然后再去它的官网上过了一遍ReadMe,发现了一些提高效率的新功能。

链接:https://github.com/nlohmann/json

using json = nlohmann::json;

namespace ns {
    void to_json(json& j, const person& p) {
        j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}};
    }

    void from_json(const json& j, person& p) {
        j.at("name").get_to(p.name);
        j.at("address").get_to(p.address);
        j.at("age").get_to(p.age);
    }
} // namespace ns

最早我们使用这个库的用法是这样的,给每个结构体定义它的 to_json 和 from_json 方法,给调用者提供模板函数来使用,借助 ADL 实现 to_json 和 from_json 的查找和调用,代码如下:(写这篇文章的时候发现这儿也用到了ADL技术,上篇文章:【建议收藏】QT实现字符串和枚举的相互转换,从源码角度分析实现原理: 也提到了,感兴趣的可以看看)。

namespace ns {
    template<class T>
    void to_string(const T &data, std::string &content)
    {
        json j;
        to_json(j, data);
        content = j.dump();
    }

    template<class T>
    void  from_string(const std::string &content, T &data)
    {
        try
        {
            json j = json::parse(content);
            from_json(j, data);
        }
        catch (exception* e)
        {}
    }
}

这种方法的优点是可以自己控制每个字段,比如字段名和结构体成员变量名可以不同,字段解析时可以增加自己的处理逻辑等等。但对于90%的使用场景来说,只想要一个简单的结构体解析,上面的方法就显得特别的繁琐。

新发现

看了 nlohmann 新的ReadMe之后,发现它提供了几个宏,很方便的就能实现结构体的json序列化和反序列化。

@brief macro
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE
@since version 3.9.0
*/
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...)  \
    friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
    friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }

#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...)  \
    friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
    friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }

/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
@since version 3.9.0
*/
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...)  \
    inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
    inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }

#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...)  \
    inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
    inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }

可以看到,这个库是3.9.0版本(2020年)才增加了这几个宏,而我们最早使用是在2019年,还没有这么简单的用法 -、-

解释:

  • NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...) 这个宏需要定义在结构体之内,它可以访问结构体/类的私有成员。
  • NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...) 这个宏需要定义在结构体之外,但需要和结构体在同一个命名空间,但不能访问结构体的私有成员,因此被序列化的字段都需要定义成public。

所以,如果你的类没有私有成员,用NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE就行了。如果你的类区分了私有成员和公有成员,用NLOHMANN_DEFINE_TYPE_INTRUSIVE就行了。

这两个宏后面带有 WITH_DEFAULT的宏的意思是当字段不存在,是否使用默认值填充。

下面是代码示例,分别展示这两个宏的用法:

namespace ns
{
    struct HardWare {
        int index = 1;
        std::string type = "AMD";
        std::string version = "0.0.1";
    };
    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(HardWare, index, type, version)
    
    struct Device {
        std::vector<HardWare> hardwarelist;
    };
    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Device, hardwarelist)
}
namespace ns {
    class address {
      private:
        std::string street;
        int housenumber;
        int postcode;

      public:
        NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(address, street, housenumber, postcode)
    };
}

在这里插入图片描述

关注公众号 QTShared,带你探索更多QT相关知识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/239659.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

人工智能导论习题集(1)

第二章&#xff1a;知识表示 题1题2题3题4题5 题1 题2 题3 题4 题5

bug-ku--计算器

F12 maxlength"1" 限制的是你能输入几位数 改成3就行 来那个数相相加就能输入了 flag{464f5f406e7e182014500fc49f7aedfc}

C++共享和保护——(1)作用域

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 人生就像骑单车&#xff0c;要想平衡就…

单元测试、系统测试、集成测试三者的区别是什么?

实际的测试工作当中&#xff0c;我们会从不同的角度对软件测试的活动进行分类&#xff0c;“单元测试&#xff0c;集成测试&#xff0c;系统测试”&#xff0c;是按照开发阶段进行测试活动的划分。这种划分完整的分类&#xff0c;其实是分为四种“单元测试&#xff0c;集成测试…

2023年最新prometheus + grafana搭建和使用+gmail邮箱告警配置

一、安装prometheus 1.1 安装 prometheus官网下载地址 sudo -i mkdir -p /opt/prometheus #移动解压后的文件名到/opt/,并改名prometheus mv prometheus-2.45 /opt/prometheus/ #创建一个专门的prometheus用户&#xff1a; -M 不创建家目录&#xff0c; -s 不让登录 useradd…

ros的slam建图和导航(含工作空间)

工作空间的结构 准备工作 创建工作空间&#xff08;ros_zy&#xff09; mkdir ros_zy进入工作空间 cd ros_zy创建src文件夹&#xff08;放源程序&#xff09; mkdir src编译工作空间 catkin_make打开vscode&#xff08;从终端打开此工程&#xff09; code .进入工作空间的…

React系列:实现子组件A->父组件-子组件B变量流传

🍁 作者:知识浅谈,CSDN博客专家,阿里云签约博主,InfoQ签约博主,华为云云享专家,51CTO明日之星 📌 擅长领域:全栈工程师、爬虫、ACM算法 💒 公众号:知识浅谈 🔥网站:vip.zsqt.cc React系列总结 🎈useState的使用 创建响应式变量的时候,在react是需要使用u…

智能监控平台/视频共享融合系统EasyCVR接入大华SDK后只有一路通道可云台控制该如何解决?

TSINGSEE青犀视频监控汇聚平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力&…

算法___

文章目录 算法两数之和两数相加 算法 两数之和 题目如下图&#xff1a; 我的答案如下图&#xff1a; 我采用的是最笨的思路&#xff0c;直接暴力的两次循环&#xff0c;第一次外循环是取数组的第一个元素&#xff0c;然后内循环会遍历数组后面除第一个的所有元素&#xff0…

LLM之RAG理论(一)| CoN:腾讯提出笔记链(CHAIN-OF-NOTE)来提高检索增强模型(RAG)的透明度

论文地址&#xff1a;https://arxiv.org/pdf/2311.09210.pdf 检索增强语言模型&#xff08;RALM&#xff09;已成为自然语言处理中一种强大的新范式。通过将大型预训练语言模型与外部知识检索相结合&#xff0c;RALM可以减少事实错误和幻觉&#xff0c;同时注入最新知识。然而&…

【上海大学数字逻辑实验报告】六、时序电路

一、 实验目的 掌握同步二进制计数器和移位寄存器的原理。学会用分立元件构成2位同步二进制加计数器。学会在Quartus II上设计单向移位寄存器。学会在Quartus II上设计环形计数器。 二、 实验原理 同步计数器是指计数器中的各触发器的时钟脉冲输入端连接在一起&#xff0c;接…

【lesson12】表的约束(5)

文章目录 表的约束的介绍外键约束测试建表插入测试建表插入测试 理解外键约束 表的约束的介绍 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合法性&#xff0c;从业务逻辑角度保证数据的正确性。…

SpringIOC之ConditionEvaluator

博主介绍:✌全网粉丝5W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌ 博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+…

C语言--与||符号介绍与短路现象

一.&&且 表达式1&&表达式2&#xff1a;表达式1为真并且表达式2为真&#xff0c;整体表达式才为真&#xff0c;其它为假。 注意短路现象&#xff1a;&#xff08;假&&假->假&#xff09;&#xff08;假&&真->假&#xff09;&#xff0c;如…

GeoPandas实操:读取数据

GeoPandas 支持读取和写入多种地理空间数据格式&#xff0c;如 ESRI Shapefile、GeoJSON、GeoPackage 等&#xff0c;以及与其他 GIS 软件兼容的格式。 1. 读取数据 1.1. 读取ESRI Shapefile数据 ESRI Shapefile&#xff08;简称 Shapefile 或 .shp 文件&#xff09;是一种常…

vue实现移动端适配

目录 1. 使用vw单位&#xff1a;vw是视窗宽度的百分比&#xff0c;可以根据不同设备的屏幕宽度来进行自适应。在Vue中可以通过设置全局CSS样式&#xff0c;将所有的尺寸单位改为vw。 2. 使用Flexible.js&#xff1a;Flexible.js是一个用于淘宝移动端适配的库&#xff0c;可以…

【lesson11】表的约束(4)

文章目录 表的约束的介绍唯一键约束测试建表插入测试建表插入测试建表插入测试修改表插入测试 表的约束的介绍 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合法性&#xff0c;从业务逻辑角度保…

实验7:索引和视图定义

【实验目的】 1、了解索引和视图的含义 2、熟悉索引和视图的创建规则 3、掌握索引和视图的创建和管理 【实验设备及器材】 1、硬件&#xff1a;PC机&#xff1b; 2、软件&#xff1a;(1)Windows7; (2)Microsoft SQL Server 2012。 【主要内容】 索引的创建、删除、重建…

C# Socket通信从入门到精通(14)——多个异步UDP客户端C#代码实现

前言: 在之前的文章C# Socket通信从入门到精通(13)——单个异步UDP客户端C#代码实现我介绍了单个异步Udp客户端的c#代码实现,但是有的时候,我们需要连接多个服务器,并且对于每个服务器,我们都有一些比如异步发送、异步接收的操作,那么这时候我们使用之前单个异步Udp客…

轻松理解 七大排序算法 (C语言实现)

目录 1. 冒泡排序 基本思想&#xff1a; 时间复杂度&#xff1a; 优化&#xff1a; 代码展示&#xff1a; 特性总结&#xff1a; 2. 直接插入排序 基本思想&#xff1a; 时间复杂度&#xff1a; 代码实现&#xff1a; 特性总结&#xff1a; 3. 简单选择排序 基…