序列化变量映射

发布于 2024-09-30 13:35:56 字数 112 浏览 9 评论 0原文

如何序列化/反序列化 boost::program_options::variables_map?我找不到已经实现的序列化函数,并且我不知道 Variables_map 中的哪些函数可以用来提取和重新组装映射。

How do I serialize/deserialize a boost::program_options::variables_map? I can't find an already implemented serialize function, and I don't know what functions in variables_map I can use to extract and reassemble the map.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

感情洁癖 2024-10-07 13:35:56

看起来您发现 boost::program_options::variables_map 派生自 std::map,因此您可以使用它的序列化(但请参阅稍后的警告)。如果唯一剩下的问题是序列化它包含的 boost::any 值,那么您就差不多了。

您无法序列化任意 boost::any 因为它并不真正知道如何操纵它所保存的内容。但是,如果您知道并且可以枚举应用程序使用的类型,则可以进行序列化。例如,如果您知道 boost::any 值始终是字符串或 int,那么类似的内容应该可以工作。

序列化(值为 boost::any):

if (value.type() == typeid(int)) {
   ar << std::string("int");
   ar << boost::any_cast<int>(value);
}
else if (value.type() == typeid(std::string)) {
   ar << std::string("string");
   ar << boost::any_cast<std::string>(value);
}

反序列化(值为 boost::any):

std::string type;
ar >> type;
if (type == "int") {
   int x;
   ar >> x;
   value = x;
}
else if (type == "string") {
   std::string x;
   ar >> x;
   value = x;
}

显然,您可以使用比“int”更有效的类型标签和序列化流中的“字符串”,但这给了您基本的想法。

编辑: boost::archive 对 const 引用很挑剔,所以我上面写的内容不能完全编译。确实如此,并且它适用于一个非常简单的测试:

enum {
   TYPE_int,
   TYPE_string,
};

namespace boost {
   namespace serialization {

      template<class Archive>
      void save(Archive& ar, const boost::program_options::variable_value& value, unsigned int version) {
         const boost::any& anyValue = value.value();
         if (anyValue.type() == typeid(int)) {
            int type = static_cast<int>(TYPE_int);
            int typedValue = boost::any_cast<int>(anyValue);
            ar << type << typedValue;
         }
         else if (anyValue.type() == typeid(std::string)) {
            int type = static_cast<int>(TYPE_string);
            std::string typedValue = boost::any_cast<std::string>(anyValue);
            ar << type << typedValue;
         }
      }

      template<class Archive>
      void load(Archive& ar, boost::program_options::variable_value& value, unsigned int version) {
         boost::any anyValue;
         int type;
         ar >> type;
         if (type == TYPE_int) {
            int x;
            ar >> x;
            anyValue = x;
         }
         else if (type == TYPE_string) {
            std::string x;
            ar >> x;
            anyValue = x;
         }

         value = boost::program_options::variable_value(anyValue, false);
      }

      template<class Archive>
      void serialize(Archive& ar, boost::program_options::variables_map& value, unsigned int version) {
         // Probably works but is sloppy and dangerous.  Would be better to
         // deserialize into a temporary std::map and build a variables_map
         // properly.  Left as an exercise.
         ar & static_cast<std::map<std::string, boost::program_options::variable_value>&>(value);
      }
   }
}

BOOST_SERIALIZATION_SPLIT_FREE(boost::program_options::variable_value);

此代码可能存在一些问题。第一个是在 load() 中的 variable_value - 最后一条语句从 boost::any 创建一个 variable_value我不太确定 bool 参数做了什么(您可能需要序列化 ​​bool 代表的任何内容)。第二个问题是,仅通过转换为 std::map 引用并反序列化,您可能会或可能不会获得一致的 variables_map。反序列化为真正的 std::map 然后从 std::map 内容构建 variables_map 会更安全。

It looks like you found out that boost::program_options::variables_map derives from std::map so you can use its serialization (but see the warning later on this). If the only remaining problem is serializing the boost::any values it contains then you're almost there.

You can't serialize an arbitrary boost::any because it doesn't really know how to manipulate what it holds. However, if you know and can enumerate the types used by your application, then serialization is possible. For example, if you know that the boost::any value is always a string or an int, then something like this should work.

To serialize (value is a boost::any):

if (value.type() == typeid(int)) {
   ar << std::string("int");
   ar << boost::any_cast<int>(value);
}
else if (value.type() == typeid(std::string)) {
   ar << std::string("string");
   ar << boost::any_cast<std::string>(value);
}

To deserialize (value is a boost::any):

std::string type;
ar >> type;
if (type == "int") {
   int x;
   ar >> x;
   value = x;
}
else if (type == "string") {
   std::string x;
   ar >> x;
   value = x;
}

Obviously you can use more efficient type tags than "int" and "string" in your serialization stream, but this gives you the basic idea.

Edit: boost::archive is picky about const references so what I wrote above doesn't quite compile. This does, and it worked for a very simple test:

enum {
   TYPE_int,
   TYPE_string,
};

namespace boost {
   namespace serialization {

      template<class Archive>
      void save(Archive& ar, const boost::program_options::variable_value& value, unsigned int version) {
         const boost::any& anyValue = value.value();
         if (anyValue.type() == typeid(int)) {
            int type = static_cast<int>(TYPE_int);
            int typedValue = boost::any_cast<int>(anyValue);
            ar << type << typedValue;
         }
         else if (anyValue.type() == typeid(std::string)) {
            int type = static_cast<int>(TYPE_string);
            std::string typedValue = boost::any_cast<std::string>(anyValue);
            ar << type << typedValue;
         }
      }

      template<class Archive>
      void load(Archive& ar, boost::program_options::variable_value& value, unsigned int version) {
         boost::any anyValue;
         int type;
         ar >> type;
         if (type == TYPE_int) {
            int x;
            ar >> x;
            anyValue = x;
         }
         else if (type == TYPE_string) {
            std::string x;
            ar >> x;
            anyValue = x;
         }

         value = boost::program_options::variable_value(anyValue, false);
      }

      template<class Archive>
      void serialize(Archive& ar, boost::program_options::variables_map& value, unsigned int version) {
         // Probably works but is sloppy and dangerous.  Would be better to
         // deserialize into a temporary std::map and build a variables_map
         // properly.  Left as an exercise.
         ar & static_cast<std::map<std::string, boost::program_options::variable_value>&>(value);
      }
   }
}

BOOST_SERIALIZATION_SPLIT_FREE(boost::program_options::variable_value);

There are a couple possible issues with this code. The first is in load() for variable_value - the last statement makes a variable_value from a boost::any and I wasn't quite sure what that bool argument did (you may need to serialize whatever that bool represents). The second is that you may or may not get a consistent variables_map by just casting to a std::map reference and deserializing. It would be safer to deserialize into a real std::map and then build the variables_map from the std::map contents.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文