msgpack:在不知道类型的情况下解压自定义 class
msgpack: Unpack custom class without knowing the type
这是我打包和解包已知 class:
的代码片段
MessageCoffeeIsReady input(1, "Black coffee is ready");
// ---- Serialize to buffer
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, input);
// ---- Send over line...
// ---- Unpack received buffer
msgpack::object_handle oh = msgpack::unpack(sbuf.data(), sbuf.size());
msgpack::object obj = oh.get();
// ---- Convert to message
MessageCoffeIsReady result; // <- How do i know the msgpack::object contains `MessageCoffeIsReady`?
obj.convert(result);
我的 class 看起来像这样:
class MessageCoffeeIsReady : public MessageBase
{
protected:
std::string m_name;
int m_id;
public:
MessageCoffeeIsReady(int id, std::string name)
{ m_id = id; m_name = name; }
MSGPACK_DEFINE (m_name, m_id);
};
我的问题是:我怎么知道我收到了 MessageCoffeIsReady
类型的消息?
有没有我可以用来转换为特定 class 的内部类型 ID?
MsgPack 是一种类似于 JSON 的格式,在其协议中不支持用户定义的类型。当您使用 MSGPACK_DEFINE
宏时,它只会映射
但是,您仍然可以添加自己的类型标签来支持诸如可区分联合之类的东西。这不会让您识别任何任意对象,但如果您只打算发送几种类型的对象中的一种,它就很适合。
struct Any {
std::string type;
msgpack::object data;
MSGPACK_DEFINE(type, data);
};
这存储了一个对象,以及一个用于标识该对象的字符串(类型)。然后就可以把对象打包进去了:
struct Foo {
int a;
std::string b;
MSGPACK_DEFINE(a, b);
};
struct Bar {
double c;
MSGPACK_DEFINE(c);
};
/* ... */
auto foo = Any { "foo", msgpack::object(Foo { 42, "hi" }, z) };
auto foo_obj = msgpack::object(foo, z);
auto bar = Any { "bar", msgpack::object(Bar { 25.5 }, z) };
auto bar_obj = msgpack::object(bar, z);
要解决问题,请先转换为 any。然后根据标签转换为不同的类型:
Any any;
obj.convert(any);
if (any.type == "foo") {
Foo foo;
any.data.convert(foo);
std::cout << "foo(a=" << foo.a << ", b=" << foo.b << ")\n";
} else if (any.type == "bar") {
Bar bar;
any.data.convert(bar);
std::cout << "bar(c=" << bar.c << ")\n";
}
当然,前提是您可以控制所看到的对象。如果你真的想要细化,你可以手动检查底层的 JSON-like 数据。这是来自文档的示例:
if (o.type != msgpack::type::ARRAY) throw msgpack::type_error();
if (o.via.array.size != 2) throw msgpack::type_error();
v = my_class(
o.via.array.ptr[0].as<std::string>(),
o.via.array.ptr[1].as<int>());
然后由您来验证您正在检查的对象是否有效。
这是我打包和解包已知 class:
的代码片段MessageCoffeeIsReady input(1, "Black coffee is ready");
// ---- Serialize to buffer
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, input);
// ---- Send over line...
// ---- Unpack received buffer
msgpack::object_handle oh = msgpack::unpack(sbuf.data(), sbuf.size());
msgpack::object obj = oh.get();
// ---- Convert to message
MessageCoffeIsReady result; // <- How do i know the msgpack::object contains `MessageCoffeIsReady`?
obj.convert(result);
我的 class 看起来像这样:
class MessageCoffeeIsReady : public MessageBase
{
protected:
std::string m_name;
int m_id;
public:
MessageCoffeeIsReady(int id, std::string name)
{ m_id = id; m_name = name; }
MSGPACK_DEFINE (m_name, m_id);
};
我的问题是:我怎么知道我收到了 MessageCoffeIsReady
类型的消息?
有没有我可以用来转换为特定 class 的内部类型 ID?
MsgPack 是一种类似于 JSON 的格式,在其协议中不支持用户定义的类型。当您使用 MSGPACK_DEFINE
宏时,它只会映射
但是,您仍然可以添加自己的类型标签来支持诸如可区分联合之类的东西。这不会让您识别任何任意对象,但如果您只打算发送几种类型的对象中的一种,它就很适合。
struct Any {
std::string type;
msgpack::object data;
MSGPACK_DEFINE(type, data);
};
这存储了一个对象,以及一个用于标识该对象的字符串(类型)。然后就可以把对象打包进去了:
struct Foo {
int a;
std::string b;
MSGPACK_DEFINE(a, b);
};
struct Bar {
double c;
MSGPACK_DEFINE(c);
};
/* ... */
auto foo = Any { "foo", msgpack::object(Foo { 42, "hi" }, z) };
auto foo_obj = msgpack::object(foo, z);
auto bar = Any { "bar", msgpack::object(Bar { 25.5 }, z) };
auto bar_obj = msgpack::object(bar, z);
要解决问题,请先转换为 any。然后根据标签转换为不同的类型:
Any any;
obj.convert(any);
if (any.type == "foo") {
Foo foo;
any.data.convert(foo);
std::cout << "foo(a=" << foo.a << ", b=" << foo.b << ")\n";
} else if (any.type == "bar") {
Bar bar;
any.data.convert(bar);
std::cout << "bar(c=" << bar.c << ")\n";
}
当然,前提是您可以控制所看到的对象。如果你真的想要细化,你可以手动检查底层的 JSON-like 数据。这是来自文档的示例:
if (o.type != msgpack::type::ARRAY) throw msgpack::type_error();
if (o.via.array.size != 2) throw msgpack::type_error();
v = my_class(
o.via.array.ptr[0].as<std::string>(),
o.via.array.ptr[1].as<int>());
然后由您来验证您正在检查的对象是否有效。