
11

一个 C++ 静态反射框架:ConfigLoader
source link: https://netcan.github.io/2021/07/10/%E4%B8%80%E4%B8%AAC-%E9%9D%99%E6%80%81%E5%8F%8D%E5%B0%84%E6%A1%86%E6%9E%B6%EF%BC%9AConfigLoader/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一个 C++ 静态反射框架:ConfigLoader
框架地址:https://github.com/netcan/config-loader
相关技术:如何优雅的实现 C++ 编译期静态反射
config-loader
是一个使用 C++17 编写的 解析配置文件 到 原生数据结构 的静态反射框架,它拥有如下特点:
- 简单的接口,用户通过 定义数据结构 与提供对应的 配置文件 ,框架利用元编程技术生成 读取 接口
- 设计符合开闭原则,扩展 数据结构 无需修改框架
- 目前支持 XML 与 JSON 格式的配置文件,多种方式可以 灵活组合
- 轻量级,容易集成,核心代码不到 1000 行
- 支持 嵌套的数据结构、STL 容器
- 测试用例完备
将来计划:
- 支持 Yaml 配置文件
- 支持从原生数据结构写到配置文件、打印数据结构
- 通过 CMake 选项来控制支持的格式
- 提供额外的 C++20 版本
使用 DEFINE_STRUCT
定义数据结构:
// define and reflect a struct
DEFINE_STRUCT(Point, // struct Point {
(double) x, // double x;
(double) y); // double y;
// };
// vector and string
DEFINE_STRUCT(SomeOfPoints, // struct SomeOfPoints {
(std::string) name, // std::string name;
(std::vector<Point>) points); // std::vector<Point> points;
// };
提供配置文件,按需加载:
SomeOfPoints someOfPoints;
auto res = JsonLoader<SomeOfPoints>().load(someOfPoints, [] {
return R"(
{
"name": "Some of points",
"points":[
{ "x": 1.2, "y": 3.4 },
{ "x": 5.6, "y": 7.8 },
{ "x": 2.2, "y": 3.3 }
]
}
)";
});
REQUIRE(res == Result::SUCCESS);
REQUIRE_THAT(someOfPoints.name, Equals("Some of points"));
REQUIRE(someOfPoints.points.size() == 3);
又或者,通过 XML 配置文件。
SomeOfPoints someOfPoints;
auto res = XMLLoader<SomeOfPoints>().load(someOfPoints, [] {
return R"(<?xml version="1.0" encoding="UTF-8"?>
<some_of_points>
<name>Some of points</name>
<points>
<value><x>1.2</x><y>3.4</y></value>
<value><x>5.6</x><y>7.8</y></value>
<value><x>2.2</x><y>3.3</y></value>
</points>
</some_of_points>
)";
});
REQUIRE(res == Result::SUCCESS);
REQUIRE_THAT(someOfPoints.name, Equals("Some of points"));
REQUIRE(someOfPoints.points.size() == 3);
有时候,你的软件系统需要一个统一的配置管理模块,管理 所有的数据结构 与 对应的配置文件,这时可以通过组合各个 Loader
来定义管理者。
inline Deserializer ConfigLoaderManager(
JsonLoader<Point>("/etc/configs/Point.json"_path),
XMLLoader<Rect>("/etc/configs/Rect.xml"_path),
JsonLoader<SomeOfPoints>() // 按需提供配置文件
);
同样地,使用 load
接口按需加载,ConfigLoaderManager
会自动根据 配置的路径 与 给定的数据结构 进行解析。你的 IDE 应该能够获得所有的 load
接口。
82 Deserializer ConfigLoaderManager(83 JsonLoader<Point>(),
84 XMLLoader<Rect>(),
85 JsonLoader<SomeOfPoints>()
86 );
87 ConfigLoaderManager.l
88 load(Rect &obj)~ f [LS]
89 load(Point &obj)~ f [LS]
90 } load(SomeOfPoints &obj, GET_CONTENT &&getContent)~ f [LS]
~ load(SomeOfPoints &obj)~ f [LS]
~ load(Rect &obj, GET_CONTENT &&getContent)~ f [LS]
~ load(Point &obj, GET_CONTENT &&getContent)~ f [LS]
当前框架依赖如下两个库:
- tinyxml2,解析 xml 配置文件用
- jsoncpp,解析 json 配置文件用
将来可能通过 CMake 选项来使能这些库,避免在实际使用中产生不必要的依赖:只用 xml 就只依赖 xml 的解析库。
本框架需要配置文件按规范的格式提供。以 XML 为例,要求字段名与 XML 标签名对应,值与 XML 的文本内容对应;对于 map
数据结构,标签通过属性 name
作为 Key 名。
当前错误码语义。
enum class Result {
SUCCESS, // 解析成功
ERR_EMPTY_CONTENT, // 解析文件为空
ERR_ILL_FORMED, // 解析文件非法
ERR_MISSING_FIELD, // 丢失字段
ERE_EXTRACTING_FIELD, // 解析值失败
ERR_TYPE, // 类型错误
};
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK