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.
-
I wrote my own serialization, but it's having trouble deserializing the boost::any's in the variable_value. – Jayen Nov 11 '10 at 07:26
-
ok, i give up. my attempt is here: http://pastebin.com/jBkA3G9x – Jayen Nov 11 '10 at 11:45
-
What about this : http://pastebin.com/jBkA3G9x/ – Mehdi Karamosly Feb 27 '13 at 07:02
-
did you mean to link to my attempt? – Jayen Feb 27 '13 at 09:45
-
Sorry I did not see your link, I guess it it did not work, best way it to inherit the class and implement `serialize` `unserialize` functions. – Mehdi Karamosly Feb 27 '13 at 15:57
-
how does inheriting help? – Jayen Feb 27 '13 at 21:29
-
inhertiing helps in many ways in your case you need to extend the class, and add some feature or functions like serialize / unserialize to it. – Mehdi Karamosly Feb 27 '13 at 21:57
-
but `boost::serialization` lets me add serialize/unserialize non-intrusively. why do i need to extend the class? – Jayen Feb 28 '13 at 00:43
-
Ok then use `boost::serialization` this is a good link about it : http://www.boost.org/doc/libs/1_53_0/libs/serialization/doc/tutorial.html – Mehdi Karamosly Feb 28 '13 at 16:16
-
I'm already using `boost::serialization`. But I can't serialize a `boost::any` with it. – Jayen Mar 01 '13 at 00:51
-
Why you can't? are the functions implemented ? Try to follow this post : http://stackoverflow.com/questions/8351299/boost-serialization-via-base-pointer-to-derived-class or this : http://stackoverflow.com/questions/10490245/virtual-functions-and-template-clash – Mehdi Karamosly Mar 01 '13 at 16:59
1 Answers
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.

- 15,650
- 2
- 52
- 80