【问题标题】:msgpack: Unpack custom class without knowing the typemsgpack:在不知道类型的情况下解压自定义类
【发布时间】:2019-11-14 14:38:31
【问题描述】:

这是我用来打包和解包已知类的代码 sn-p:

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 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 类型的消息?

是否有任何内部 typeid 可用于转换为特定类?

【问题讨论】:

    标签: c++ msgpack


    【解决方案1】:

    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 的数据。以下是文档中的示例:

    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>());
    

    然后由您来验证您正在检查的对象是否有效。

    【讨论】:

    • 我需要“z”(区域)吗?我收到以下警告:“对 `msgpack::v1::adaptor::object::operator()(msgpack::v2::object&, Foo const&) const' 的未定义引用”。谢谢。
    • 我相信是的。示例中的z 是一个 msgpack::zone,它为对象分配并拥有内存。只需将msgpack::zone z; 粘贴在示波器顶部,您就可以开始使用了
    • 谢谢,它有效! @parktomatomi,伟大而灵活的解决方案,谢谢!
    • 您可以使用(std 或 boost)变体做类似的事情。这是一个升压变体示例。 wandbox.org/permlink/abciRlOK3T1EhpJs 注意:boost::typeindex::type_id&lt;decltype(e)&gt;().pretty_name() 是实现定义的。
    猜你喜欢
    • 1970-01-01
    • 2012-09-19
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多