【问题标题】:Order-independent input archive for boost serialization用于提升序列化的与订单无关的输入存档
【发布时间】:2025-12-19 10:10:12
【问题描述】:

我使用 boost::serialization 并且非常喜欢它。我有时会想念的唯一一件事是,当我想从 xml 存档中读取配置输入结构时。那就太好了,如果

  1. xml 结构可以是顺序无关的,并且
  2. 如果 xml 中缺少对象,将采用类的默认值。

这主要是用于 boost::serialization 还是您已经有解决方案?

【问题讨论】:

    标签: c++ xml boost boost-serialization


    【解决方案1】:

    因为我认为show-don't-tell 更有建设性,以下是我认为您在使用 Boost Property Tree 之后的示例:

    Live On Coliru

    #include <boost/property_tree/ptree.hpp>
    #include <boost/property_tree/xml_parser.hpp>
    
    struct Config {
        std::string order;
        double independent;
        std::string stuff;
    
        static Config load_xml(std::istream& from) {
            boost::property_tree::ptree pt;
            read_xml(from, pt);
    
            return {
                pt.get("order", "default property value for order"),
                pt.get("independent", 42.0),
                pt.get("stuff", "no stuff configured")
            };
        }
    
        void save_xml(std::ostream& to) const {
            boost::property_tree::ptree pt;
    
            if (!order.empty())   pt.put("order",       order);
            if (independent != 0) pt.put("independent", independent);
            if (!stuff.empty())   pt.put("stuff",       stuff);
    
            write_xml(to, pt);
        }
    };
    
    #include <iostream>
    
    int main() {
        {
            Config cfg { "order", 999, "stuff" };
            cfg.save_xml(std::cout);
        }
    
        std::istringstream iss("<independent>3.1415926535897931</independent><IGNORED>stuff</IGNORED><order>LOOK MA</order>");
    
        Config::load_xml(iss).save_xml(std::cout);
    }
    

    哪些打印:

    <?xml version="1.0" encoding="utf-8"?>
    <order>order</order><independent>999</independent><stuff>stuff</stuff>
    <?xml version="1.0" encoding="utf-8"?>
    <order>LOOK MA</order><independent>3.1415926535897931</independent><stuff>no stuff configured</stuff>
    

    【讨论】:

      【解决方案2】:

      序列化不是为了这个。

      当然你可以让你序列化的东西与顺序无关:

      #include <boost/serialization/map.hpp>
      
      struct MyConfig {
          std::map<std::string, std::string> values;
      
          template<typename Ar> void serialize(Ar& ar, unsigned) {
              ar & values;
          }
      };
      

      阅读的顺序无关紧要。

      此外,您已经可以使用可选的默认值(提示:它与序列化完全无关):

      struct MyConfig {
          std::string const& workingDirectory() {
              return *values.emplace("workingdir", "$HOME").first;
          }
      
        private:
          std::unordered_map<std::string, std::string> values;
      };
      

      这里workingDirectory() 将返回对反序列化值的引用。如果不存在这样的值,则会先插入"$HOME"

      但是

      对于这种情况,您应该考虑使用Boost Property Tree。它更适合这个目的。

      【讨论】:

      • 感谢您的回答。没错,使用 xml 解析器,如 boost 属性树,会更容易实现要求。但是,最好使用 boost 序列化来避免并行结构和数据类型转换。使用映射读取无序列表的缺点是数据类型是固定的,在您的示例中为字符串。
      • 作为记录,Boost Property Tree 不是 XML 解析器。您是否考虑过使用std::map&lt;std::string, boost::variant&lt;std::string, double, bool, ...&gt; &gt;
      • 问题是设置类是模块化的,所以一个设置类的对象往往是另一个设置类,也可以是多态的。因此,我有许多不同的数据类型,使用 boost 变体很难维护。
      • 也许您应该考虑发布实际问题,而不是一次添加更多约束。我认为这个问题现在已经结束了
      【解决方案3】:

      here 是我的实验性 boost::serialization 存档,它能够序列化为 boost::property_tree。

      默认情况下,生成的 ptree 以适合 json 或 info 格式的方式创建,但只需稍作修改即可针对 xml 进行优化。

      它可以按任意顺序加载字段,其他字段也将被忽略(这允许一些向前兼容性)。

      当前错过的字段将产生错误。引入具有默认值的可选字段需要一些额外的工作。

      还有一个用于 xml 存档的 patch 允许跳过未知字段,但它不允许任意顺序或可选字段。

      【讨论】:

        最近更新 更多