c++实现Json配置数据序列化和反序列化

本文介绍了如何使用C++实现Json配置数据的序列化和反序列化,背景是由于配置参数的复杂性选择了Json格式。通过静态反射技术,实现了结构体与Json之间的转换。文中提供了结构体定义、反序列化和序列化的原理,以及使用示例,包括读取和写入接口的说明。

参考资料:

参考资料:https://zhuanlan.zhihu.com/p/388454455

参考github地址:https://github.com/netcan/config-loader

背景

最近在做一个可配置系统的参数设置工具时,由于参数数量众多,包含多层树结构,并且参数之间还会有相互关系。

配置参数的读写,从技术选型上有ini,xml,json。由于ini原生不支持树结构,需要根据需要将父节点的option作为子节点的section,配置文件可读性变差。xml由于属性和元素分开的形式,不适合直接转为c++定义的树状结构。所有最终选择了json。

要想用c++实现一个通用的json文件序列化和反序列化工具,反射是绕不开的。c++语言原生不支持反射,因此要通过一些编程技巧实现。在查阅资料过程中发现了configloader,clone学习过程中发现该代码库目前仅实现了json文件的读取,写入还没有实现,因此,狗尾续貂,实现了json文件的写入,勉强是满足了笔者的项目需求。

原理

结构体定义

使用宏包装的结构体定义方法,包含了编译期字段数量计算,每个字段的名称和变量的封装,每个字段是否是最后一个字段判断(用来序列号json时最后一个字段不加“,”)。

#define DEFINE_SCHEMA(st, ...)                                                          \
    struct st {                                                                         \
        template <typename, size_t> struct FIELD;                                       \
        static constexpr size_t _field_count_ = GET_ARG_COUNT(__VA_ARGS__);             \
        static constexpr decltype(#st) _schema_name_ = #st;                             \
        EXPAND(PASTE(REPEAT_, GET_ARG_COUNT(__VA_ARGS__)) (FIELD_EACH, 0, __VA_ARGS__)) \
    }                                                                                   \

每个字段

#define FIELD_EACH(i, arg)                     \
    PAIR(arg);                                 \
    template <typename T>                      \
    struct FIELD<T, i> {                       \
        T& obj;                                \
        FIELD(T& obj): obj(obj) {}             \
        auto value() -> decltype(auto) {       \
            return (obj.STRIP(arg));           \
        }                                      \
        static constexpr const char* name() {  \
            return EXPAND(STRING(STRIP(arg))); \
        }                                      \
        static constexpr const bool isLast() { \
            return i==(_field_count_-1);       \
        }                                      \
    };                                         \

反序列化

反序列化时,使用jsoncpp解析json文件,然后采用递归的方式将json文件中的值填充到结构体中。

递归时,会根据当前节点的类型,选择对应的特化模板结构体中的反序列号函数。

序列化

序列化时,同样采用递归的方式。

//针对自定义结构体
static void dump(std::ostream& out, const T& obj, size_t depth = 0) 
{
    out << "{";
    forEachField(obj, [&out, depth](auto&& fieldInfo) {
        decltype(auto) fieldName = fieldInfo.name();
        decltype(auto) value = fieldInfo.value();
        out << "\n" << detail::indent(depth + 1) << "\"" << fieldName << "\"" <<":";
        dump(out, value, depth + 1);
        //如果是最后一个字段,则不加入","
        if(!fieldInfo.isLast())
            out << ",";
    });
    out << "\n" << detail::indent(depth) << "}";
}
//针对基本数据类型
static void dump(std::ostream& out, const T& obj, size_t = 0) 
{
	dump(out, obj);
}
//针对数字
static void dump(std::ostream& out, Number number) 
{
	out << number;
}
//针对字符串
static void dump(std::ostream& out, const std::string& str) 
{
	out << "\"" << str << "\"";
}

以上函数,被包含到一个模板结构体中。采用同一套模板,根据不同类型偏特,每种类型有各自的实现。

用法示例

结构体定义

DEFINE_SCHEMA(CorrectPara,
	(int) bUseCorrect,
	(int) eCorrectType,
	(int) bAutoCorrect,
	(int) nCorrectPeriod,
	(int) nFilterRadius
);


DEFINE_SCHEMA(FilterSize,
	(int) nW,
	(int) nH,
	(int) nShift
);


DEFINE_SCHEMA(FilterPara,
	(int) bUseFilter,
	(FilterSize) szFilterSize0,
	(FilterSize) szFilterSize1
);

DEFINE_SCHEMA(ChannelPara,
	(int) bChannelValid,
	(FilterPara) filterPara
);


DEFINE_SCHEMA(Params,
	(CorrectPara) CorrectPara,
	(ChannelPara) ch0Para,
	(ChannelPara) ch1Para
);

使用方法

	Params paras;
	auto ret = ReadJSONConfig(paras, "Params.json");
	//当前暂不支持vector容器的序列化
	WriteJsonConfig(paras, "ParamsEx.json");

仅两个接口,一个读取,一个写入。
读写的内容如下:

{
  "CorrectPara":{
    "bUseCorrect":0,
    "eCorrectType":1,
    "bAutoCorrect":2,
    "nCorrectPeriod":100,
    "nFilterRadius":3
  },
  "ch0Para":{
    "bChannelValid":1,
    "filterPara":{
      "bUseFilter":1,
      "szFilterSize0":{
        "nW":128,
        "nH":128,
        "nShift":14
      },
      "szFilterSize1":{
        "nW":4,
        "nH":4,
        "nShift":4
      }
    }
  },
  "ch1Para":{
    "bChannelValid":1,
    "filterPara":{
      "bUseFilter":1,
      "szFilterSize0":{
        "nW":64,
        "nH":64,
        "nShift":12
      },
      "szFilterSize1":{
        "nW":2,
        "nH":32,
        "nShift":6
      }
    }
  }
}

资源下载地址

https://download.csdn.net/download/iamqianrenzhan/86501805

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

元点机智

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值