想写一个方便无比的配置保存类,但 ms 实现不了?求集思广益! - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
rtyurtyu
V2EX    C

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

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

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

    //公有成员变量
    int setting1;//配置数据 1
    doube 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     Solana     2867 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 14:09 PVG 22:09 LAX 06:09 JFK 09:09
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86