10

boost::program_options::variables_map をシリアライズ/デシリアライズするにはどうすればよいですか? 既に実装されているシリアル化関数が見つかりません。マップを抽出して再構築するために使用できる variables_map の関数もわかりません。

4

1 に答える 1

10

boost::program_options::variables_mapから派生したことがわかったようですstd::mapので、そのシリアル化を使用できます(ただし、これについては後で警告を参照してください)。残っている唯一の問題がboost::any含まれている値のシリアル化である場合は、ほぼ完了です。

任意の boost::any をシリアル化することはできません。これは、それが保持するものを操作する方法を本当に知らないためです。ただし、アプリケーションで使用される型を知っていて列挙できる場合は、シリアル化が可能です。たとえば、boost::any値が常に文字列または整数であることがわかっている場合は、次のようなものが機能するはずです。

シリアル化するには (値は 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);
}

逆シリアル化するには (値は 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;
}

シリアライゼーション ストリームでは、"int" や "string" よりも効率的な型タグを使用できることは明らかですが、これで基本的な考え方がわかります。

編集: boost::archiveconst 参照についてうるさいので、上で書いたものは完全にコンパイルされません。これはそうです、そしてそれは非常に単純なテストでうまくいきました:

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()for ですvariable_value- 最後のステートメントはvariable_valuefrom aboost::anyを作成しますが、その引数が何をしたのかよくわかりませんboolでした (それが表すものをシリアル化する必要があるかもしれませんbool)。variables_map2 つ目は、参照にキャストしてstd::map逆シリアル化するだけでは、一貫性が得られる場合と得られない場合があるということです。実数にデシリアライズしてから、コンテンツからstd::mapを構築する方が安全です。variables_mapstd::map

于 2013-03-02T20:35:29.713 に答える