msgpack — десериализация гетерогенной карты с помощью MessagePack в переполнении стека

Я использую 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 содержит только тривиальные примеры, и этот блог лучше, но не охватывает этот вариант использования.

5

Решение

Вы можете сделать это используя 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.

1

Другие решения

Я закончил понтовать на этом и писать мой собственный текстовый формат сериализации. Как правило, он не так полезен, как MessagePack, но позволяет мне справиться с этими статическими проблемами.

0

По вопросам рекламы [email protected]