V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
rtyurtyu
V2EX  ›  C

想写一个方便无比的配置保存类,但 ms 实现不了?求集思广益!

  •  
  •   rtyurtyu · 2016-06-18 18:54:35 +08:00 · 2487 次点击
    这是一个创建于 3080 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我先大致描述这个类是什么样子的:
    class SaveClass
    {
    private:
    //各种私有方法和变量
    //...

    public:
    //公有方法
    read(char * filename);//从 filename 读入配置
    save(char * filename);//写入配置到 filename

    //公有成员变量
    int setting1;//配置数据 1
    double setting2;//配置数据 2
    std::string setting3;//配置数据 3

    }
    SaveClass cSave;

    setting1 、 setting2 、 setting3 就是配置数据
    直接在类定义里添加
    这样可以方便的
    cSave.setting1=123;
    cSave.setting2=0.456;
    cSave.setting3="abc 啊啊啊";
    来读取和设置

    关键点来了!
    当 cSave.save("C:\sav.ini")的时候,要能自动写入 sav.ini 如下内容:
    setting1=123;
    setting2=0.456;
    setting3=abc 啊啊啊;
    当 cSave.read("C:\sav.ini")的时候,要能自动读入配置文件到对应变量

    关键就是自动枚举类中的成员变量,自动把变量名转字符串,自动判断变量名的类型
    也就是说我添加一个新成员变量 float setting4 的时候,不需要改写.save 方法和.init 方法就能自动适应

    如果用 javascript 来做的话用 eval 、 tostring 等等可以很轻易的实现
    但是 c++没有这么方便的函数
    算上宏算上模板能不能想办法来用 c++实现设想的这个功能?
    16 条回复    2016-06-19 13:07:11 +08:00
    h4x3rotab
        1
    h4x3rotab  
       2016-06-18 19:34:40 +08:00 via iPhone
    搜索关键词: c++ 序列化
    rogerchen
        2
    rogerchen  
       2016-06-18 19:49:02 +08:00
    protocol buffer
    skydiver
        3
    skydiver  
       2016-06-18 19:54:44 +08:00 via iPad
    用宏实现
    rtyurtyu
        4
    rtyurtyu  
    OP
       2016-06-18 20:08:01 +08:00
    我需要文本式的序列化而不能是看不懂的二进制形式的,因为有双击.ini 直接编辑配置文件的需求
    如果没有直接编辑的需求那最简单的直接二进制写一个 struct 到文件就搞定了
    看了看现有的库好像都不太合适的样子
    还是想完全自写
    sfqtsh
        5
    sfqtsh  
       2016-06-18 20:12:28 +08:00 via Android
    #include <iostream>
    using namespace std;

    #define DefineVar(type, name, value) #type" "#name" = ";type name = value
    int main()
    {
    char str[] = DefineVar(int, iAbc, 8);
    cout << str << iAbc << endl; //"int iAbc = 8"

    return 0;
    }
    sfqtsh
        6
    sfqtsh  
       2016-06-18 20:18:58 +08:00 via Android
    为什么个人主页里找不到自己在 C/C++/Obj-C 节点里的回复?好几次了 @Livid
    k9982874
        7
    k9982874  
       2016-06-18 20:20:02 +08:00 via iPad
    boost property_tree 操作 ini
    tinyxml 操作 xml
    jsoncpp 操作 json

    没必要自己再造轮子
    Sorrow
        8
    Sorrow  
       2016-06-18 20:26:55 +08:00 via iPad
    使用 boost::any 可以存放任意类型的数据,或者直接使用 c++ 17 的 std::any
    rtyurtyu
        9
    rtyurtyu  
    OP
       2016-06-18 20:39:47 +08:00
    @skydiver
    @sfqtsh
    想了想好像用宏是可以实现的,虽然要写的很复杂
    就在类定义里直接一个宏把 save 、 read 和变量定义都改写出来

    @k9982874
    还是希望最精简的语法 cSave.xxx=n 就能直接读写配置,重载了=甚至可以省略.save 实时保存
    你这些类都会让语法更复杂

    @Sorrow
    不想用 boost 实在是太臃肿了
    Sorrow
        10
    Sorrow  
       2016-06-18 20:52:00 +08:00 via iPad
    @rtyurtyu std::any 已经在最近版本的 c++ 标准库里了, 只要包含相应头文件就行了。
    matthewgao
        11
    matthewgao  
       2016-06-19 00:31:26 +08:00
    @Sorrow any 好像也不解决他的问题,他是要一个类似 Java 反射的功能
    matthewgao
        12
    matthewgao  
       2016-06-19 00:37:33 +08:00
    可不可以这样 workaround 一下,用 unordered_map<std::string, std::any>来保存你要解析的属性,就不要把它变成真正的类属性
    owt5008137
        13
    owt5008137  
       2016-06-19 00:42:07 +08:00
    C++目前还不支持反射,是做不到像 Java 或者 C#那样枚举成员变量的。用宏只是一点点取巧而已,也不是特别方便,可以参考 msgpack-c 的设计,就是宏实现的。

    用 protobuf 之类的可能是简单得多的方案了,特别是 protobuf 3 可以直接读写 json ,用它的反射接口写序列化和反序列化也不困难。但是还是得写 proto 文件,并且 protobuf 也是蛮臃肿的。

    或者寻求简洁的话可以参考下我的这个 ini 读取库,只有两个文件。 https://github.com/owt5008137/libiniloader
    用 std::string 来存数据,用模板来自动检测类型,转换数据内容
    nozama
        14
    nozama  
       2016-06-19 02:48:45 +08:00 via iPhone
    我猜最多只能用 宏、模板鸡肋地实现,或者代码生成器(比如 protobuf....好像太重量级)。

    这我想起 rust 的好了,编译器扩展也可以是 library 的一部分,有不少序列化库都利用了这一点,借助编译时的信息来生成代码,可以非侵入式地实现序列化 /反序列化。

    我更想说的是,用合适的工具做合适的事、合理地分离关注点,比对语言进行晦涩的 hack 要好。
    rtyurtyu
        15
    rtyurtyu  
    OP
       2016-06-19 06:07:37 +08:00
    看了 ls 各位的意见又想了很多,突然感觉追求个最精简语法.xxx=x 没有什么意义,非要用静态语言来搞动态语言的事纯粹是找虐

    如果用宏来实现,变量定义那里语法仍然怪怪的,宏也复杂得让人看不懂
    而且每次新加一个变量都需要改源码重新编译

    不如就用 unordered_map<std::string, std::any> cSave;
    好处是代码易读,而且能够动态添加
    cSave["aaa"]=111;
    写起来比 cSave.aaa=111 只多三个字符,就是引号有点烦...

    当然现在 std::any 的支持度为 0 ,实际实现还得用一些替代方法
    jukka
        16
    jukka  
       2016-06-19 13:07:11 +08:00
    最简单的做法是继承一个 Lua 虚拟机进去,然后这些事情都在 Lua 里完成。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2701 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 10:36 · PVG 18:36 · LAX 02:36 · JFK 05:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.