Wie serialisiere/deserialisiere ich eine boost::program_options::variables_map? Ich kann keine bereits implementierte serialize-Funktion finden, und ich weiß nicht, welche Funktionen in variables_map ich verwenden kann, um die Karte zu extrahieren und wieder zusammenzusetzen.
Antwort
Zu viele Anzeigen?Es sieht so aus, als hätten Sie herausgefunden, dass boost::program_options::variables_map
leitet sich ab von std::map
so dass Sie seine Serialisierung verwenden können (siehe aber die Warnung weiter unten). Wenn das einzige verbleibende Problem die Serialisierung der boost::any
Werte enthält, sind Sie fast am Ziel.
Ein beliebiges boost::any kann nicht serialisiert werden, da es nicht weiß, wie es den Inhalt manipulieren soll. Wenn Sie jedoch die von Ihrer Anwendung verwendeten Typen kennen und aufzählen können, dann ist eine Serialisierung möglich. Wenn Sie zum Beispiel wissen, dass der boost::any
Wert ist immer ein String oder ein int, dann sollte so etwas funktionieren.
Zum Serialisieren (Wert ist ein 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);
}
Zum Deserialisieren (Wert ist ein 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;
}
Natürlich können Sie in Ihrem Serialisierungsstrom effizientere Typ-Tags als "int" und "string" verwenden, aber dies vermittelt Ihnen die grundlegende Idee.
Bearbeiten: boost::archive
ist pingelig bei const-Referenzen, so dass das, was ich oben geschrieben habe, nicht ganz kompilierbar ist. Dies tut, und es funktionierte für einen sehr einfachen 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);
Es gibt einige mögliche Probleme mit diesem Code. Das erste liegt in load()
para variable_value
- die letzte Aussage macht eine variable_value
von einer boost::any
und ich war mir nicht ganz sicher, was das bool
Argument (möglicherweise müssen Sie das, was Sie bool
vertritt). Zweitens kann es sein, dass Sie eine konsistente variables_map
durch einfaches Anwenden eines std::map
Referenz und Deserialisierung. Es wäre sicherer, die Deserialisierung in eine echte std::map
und bauen dann die variables_map
von der std::map
Inhalt.