8

一个 C++ 静态反射框架:ConfigLoader

 3 years ago
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.
neoserver,ios ssh client

一个 C++ 静态反射框架:ConfigLoader

2021.07.10

Netcan

编程

 热度 14℃

框架地址: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

  • 48
    • tech.meituan.com 5 years ago
    • Cache

    Hades:移动端静态分析框架

    只有通过别人的眼睛,才能真正地了解自己 ——《云图》 背景 作为全球最大的互联网 + 生活服务平台,美团点评近年来在业务上...

  • 56
    • 微信 mp.weixin.qq.com 4 years ago
    • Cache

    LWN: 针对GCC的静态分析框架!

    关注了就能看到更多这么棒的文章哦~ A static-analysis framework for GCC By  Jake Edge December 4, 2019 原文来自:https://lwn.net/Articles/806099/...

  • 17
    • 掘金 juejin.im 4 years ago
    • Cache

    万字总结之反射(框架之魂)

    前言准备过年看下Spring源码,用来唬人,哈哈哈哈。正经点,是为了在遇到问题的时候,能知其然而知其所以然。但是在开始前,先恶补下基础知识。今天看框架之魂——反射。反射的概述(基础部分开始)反射是在编译状态,对某个类一无所知 ,但在运行状态中,对于任意一...

  • 7
    • zhuanlan.zhihu.com 3 years ago
    • Cache

    如何优雅的实现C++编译期静态反射

    如何优雅的实现C++编译期静态反射netcanC++程序猿, 公众号:高级开发者原文链接:

  • 9

    如何优雅的实现 C++ 编译期静态反射 2020.08.01 Netcan 编程...

  • 8
    • blog.lpflpf.cn 2 years ago
    • Cache

    Golang反射学习:手写一个RPC

    本文主要为了在对golang反射学习后做一个小练习,使用100行代码实现一个通用的RPC服务。 golang 的RPC框架还是非常丰富的,比如 gRPC,go-zero, go-dubbo 等都是使用非常普遍的rpc框架。在go语言实现的RPC客户端中,大部分RPC框架采用的是使用生成代码...

  • 7
    • fuzhe1989.github.io 1 year ago
    • Cache

    C++:一个极简的静态反射 demo

    C++:一个极简的静态反射 demo 2022-11-09...

  • 0
    • studygolang.com 1 year ago
    • Cache

    golang反射框架Fx

    golang反射框架Fx 神奇的考拉 · 2019-02-02 19:34:43 · 4402 次点击 · 预计阅读时间 10 分钟 · 大约8小时之前 开始浏览     ...

  • 4

    Java ”框架 = 注解 + 反射 + 设计模式“ 之 注解详解

  • 5

    在《深入剖析Java中的反射,由浅入深,层层剥离!》这篇文章中我们讲反射时,曾提到过Java的动态代理中使用了反射技术,那么好,今天我们要就着反射的索引,来学习一下Java中的代理!

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK