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.
Boost. ProgramOptions is a library that makes it easy to parse command-line options, for example, for console applications. If you develop applications with a graphical user interface, command-line options are usually not important. To parse command-line options with Boost.
The library Boost. Serialization makes it possible to convert objects in a C++ program to a sequence of bytes that can be saved and loaded to restore the objects. There are different data formats available to define the rules for generating sequences of bytes. All of the formats supported by Boost.
Some boost libraries are header-only, some are not, and for various reasons etc.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With