Похоже, вы узнали, что boost::program_options::variables_map
происходит от std::map
, поэтому вы можете использовать его сериализацию (но см. Предупреждение позже).Если единственной оставшейся проблемой является сериализация значений boost::any
, которые он содержит, то вы почти на месте.
Вы не можете сериализовать произвольное повышение :: любой, потому что он действительно не знает, как манипулировать тем, что ондержит.Однако, если вы знаете и можете перечислять типы, используемые вашим приложением, возможна сериализация.Например, если вы знаете, что значение boost::any
всегда является строкой или целым числом, то что-то вроде этого должно работать.
Для сериализации (значение равно 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);
}
Для десериализации (значение равно 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" в потоке сериализации, но это дает вам основныеidea.
Редактировать: boost::archive
требователен к константным ссылкам, поэтому то, что я написал выше, не совсем компилируется.Это так, и это сработало для очень простого теста:
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()
для variable_value
- последнее выражение делает variable_value
из boost::any
, и я не совсем уверен, что сделал этот аргумент bool
(вам может понадобиться сериализовать все, что bool
представляет собой).Во-вторых, вы можете получить или не получить согласованный variables_map
, просто приведя к std::map
ссылку и десериализацию.Было бы безопаснее десериализовать в реальный std::map
, а затем собрать variables_map
из содержимого std::map
.