Comment sérialiser/désérialiser un boost :: program_options :: variables_map? Je ne peux pas trouver une fonction serialize déjà implémentée, et je ne sais pas quelles fonctions dans variables_map je peux utiliser pour extraire et réassembler la carte.Sérialisation d'une variable_map
Répondre
Il semblerait que vous ayez découvert que boost::program_options::variables_map
dérive de std::map
afin que vous puissiez utiliser sa sérialisation (mais voir l'avertissement plus loin). Si le seul problème restant est de sérialiser les valeurs boost::any
qu'il contient alors vous êtes presque là.
Vous ne pouvez pas sérialiser un boost :: quelconque car il ne sait pas vraiment comment manipuler ce qu'il contient. Cependant, si vous connaissez et pouvez énumérer les types utilisés par votre application, la sérialisation est possible. Par exemple, si vous savez que la valeur boost::any
est toujours une chaîne ou un int, alors quelque chose comme ça devrait fonctionner.
Pour sérialiser (valeur est une 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);
}
désérialiser (valeur est une 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;
}
Évidemment, vous pouvez utiliser des balises de type plus efficaces que "int" et " chaîne "dans votre flux de sérialisation, mais cela vous donne l'idée de base.
Editer: boost::archive
est pointilleux sur les références const donc ce que j'ai écrit ci-dessus ne compile pas tout à fait. Cela fonctionne, et cela a fonctionné pour un test très simple:
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);
Il existe plusieurs problèmes avec ce code. Le premier est dans load()
pour variable_value
- la dernière déclaration fait un variable_value
à partir d'un boost::any
et je ne savais pas exactement ce que cet argument bool
a fait (vous devrez peut-être sérialiser tout ce que bool
représente). La seconde est que vous pouvez ou ne pouvez pas obtenir un variables_map
cohérent simplement en castant à une référence std::map
et désérialisant. Il serait plus sûr de désérialiser en un vrai std::map
puis de construire le variables_map
à partir du contenu std::map
.
Quelle réponse, si complète ... +1. –
J'ai écrit ma propre sérialisation, mais il a du mal à désérialiser le boost :: any dans la variable_value. – Jayen
ok, j'abandonne. ma tentative est ici: http://pastebin.com/jBkA3G9x – Jayen
Qu'en est-il: http://pastebin.com/jBkA3G9x/ –