Я использую MessagePack с C ++ и пытаюсь десериализовать эквивалент этой карты Python:
{'metadata': {'date': '2014-06-25', 'user_id': 501},
'values': [3.0, 4.0, 5.0],
'version': 1}
Объект верхнего уровня — это карта со строковыми ключами, но значения имеют совершенно разные типы. Мой код заранее знает, какой должна быть структура объекта; Я должен иметь возможность объявить целое число, а затем сказать свой код десериализации: «Значение version
ключ — это целое число, поэтому поместите значение этого целого в этот адрес памяти ».
Проблема в том, что я даже не уверен, как добраться до точки, где мой код C ++ может рассматривать эту структуру как карту. Я ожидал бы сделать что-то вроде
msgpack::unpacker unpacker;
// ...copy the data into unpacker's buffer...
msgpack::unpacked message;
std::map<std::string, anything> output_map;
unpacker.next(&message);
msgpack::object obj = message.get();
obj.convert(&output_map);
int version_number = output_map.at("version");
Есть ли возможный тип (anything
) что будет работать здесь? Документация MessagePack содержит только тривиальные примеры, и этот блог лучше, но не охватывает этот вариант использования.
Вы можете сделать это используя boost :: option. Для реализации рекурсивной структуры вы можете использовать oost :: make_recursive_variant следующим образом:
typedef boost::make_recursive_variant<
std::string,
std::map<boost::recursive_variant_, boost::recursive_variant_>,
std::vector<boost::recursive_variant_>,
int,
double
>::type variant_t;
Вот документация:
http://www.boost.org/doc/libs/1_55_0/doc/html/variant/tutorial.html#variant.tutorial.recursive.recursive-variant
Вам также нужно написать конвертер, который преобразует из msgpack :: object в variable_t и наоборот следующим образом:
// Custom converter for variant_t
namespace msgpack {
// Convert from msgpacl::object to variant_t.
inline variant_t& operator>>(object const& o, variant_t& v) {
switch(o.type) {
case type::MAP:
v = std::map<variant_t, variant_t>();
o.convert(boost::get<std::map<variant_t, variant_t> >(&v));
break;
case type::ARRAY:
v = std::vector<variant_t>();
o.convert(boost::get<std::vector<variant_t> >(&v));
break;
case type::POSITIVE_INTEGER:
v = int();
o.convert(boost::get<int>(&v));
break;
case type::DOUBLE:
v = double();
o.convert(boost::get<double>(&v));
break;
case type::RAW:
v = std::string();
o.convert(boost::get<std::string>(&v));
break;
default:
break;
}
return v;
}// Convert from variant_t to msgpacl::object.
template <typename Stream>
struct packer_imp:boost::static_visitor<void> {
template <typename T>
void operator()(T const& value) const {
o_.pack(value);
}
packer_imp(packer<Stream>& o):o_(o) {}
packer<Stream>& o_;
};
template <typename Stream>
inline packer<Stream>& operator<< (packer<Stream>& o, const variant_t& v)
{
boost::apply_visitor(packer_imp<Stream>(o), v);
return o;
}
} // namespace msgpack
Вы можете получить полный пример кода из gist:
https://gist.github.com/redboltz/672c5af16b2907488977
В этом примере я использовал функцию C ++ 11, поэтому вам нужно добавить опцию -std = c ++ 11.
Я закончил понтовать на этом и писать мой собственный текстовый формат сериализации. Как правило, он не так полезен, как MessagePack, но позволяет мне справиться с этими статическими проблемами.