【问题标题】:MessagePack, c++: How to use MSGPACK_DEFINE with c++11 enum classesMessagePack,c++:如何将 MSGPACK_DEFINE 与 c++11 枚举类一起使用
【发布时间】:2013-12-07 22:09:18
【问题描述】:

以下示例无法编译,抱怨

In file included from /usr/include/msgpack.hpp:18:
/usr/include/msgpack/object.hpp:211:3: error: member reference base type 'logd::log_level' is not a structure or union

以及其他枚举类的相应错误。我的问题是,如何使用 msgpack 的 c++ api 序列化具有 c++11 enum class 类型成员的类?

#ifndef LOG_MSG_HPP_
#define LOG_MSG_HPP_

#include <stdlib.h>
#include <msgpack.hpp>

/** @namespace logd */
namespace logd {

enum class log_level { SILENT,... DEBUG };

enum class log_domain { AI, ...  MISC };

class log_msg {
    public:
        log_msg(log_level lev, log_domain dom, std::string msg);
        log_level level();
        log_domain domain();
        std::string message();
        ~log_msg();
        MSGPACK_DEFINE(lev_, dom_, msg_);

    private:
        log_msg();
        log_level   lev_ {log_level::DEBUG};
        log_domain  dom_ {log_domain::MISC};
        std::string msg_ {"No message given."};
};
} /* namespace logd */
#endif /* LOG_MSG_HPP_ */

注意:由于枚举是我的,我可以很高兴地修改它们以使 msgpack 满意。不幸的是,我在他们的文档或谷歌的前几页中找不到关于这个主题的参考资料。我也无法通过阅读他们的标题/源来确定要做什么,因为我对 c++ 还很陌生。

【问题讨论】:

    标签: c++ serialization c++11 enums msgpack


    【解决方案1】:

    您可以使用 MSGPACK_ADD_ENUM() 宏。从 1.0.0 版本开始支持它。我推荐版本 1.1.0 或更高版本。

    见: https://github.com/msgpack/msgpack-c/wiki/v1_1_cpp_adaptor#enums

    我将 MSGPACK_ADD_ENUM() 应用于您的代码:

    #ifndef LOG_MSG_HPP_
    #define LOG_MSG_HPP_
    
    #include <stdlib.h>
    #include <msgpack.hpp>
    
    /** @namespace logd */
    namespace logd {
    
    enum class log_level { SILENT,DEBUG };
    
    enum class log_domain { AI, MISC };
    
    class log_msg {
        public:
            log_msg(log_level lev, log_domain dom, std::string msg):lev_(lev), dom_(dom), msg_(msg) {}
            log_level level() { return lev_;}
            log_domain domain() { return dom_;}
            std::string message() { return msg_; }
            ~log_msg() {}
            MSGPACK_DEFINE(lev_, dom_, msg_);
            log_msg() = default;
    
        private:
            log_level   lev_ {log_level::DEBUG};
            log_domain  dom_ {log_domain::MISC};
            std::string msg_ {"No message given."};
    };
    } /* namespace logd */
    
    MSGPACK_ADD_ENUM(logd::log_level);
    MSGPACK_ADD_ENUM(logd::log_domain);
    
    
    #endif /* LOG_MSG_HPP_ */
    
    #include <sstream>
    #include <cassert>
    
    int main() {
        logd::log_msg lm { logd::log_level::SILENT, logd::log_domain::AI, "hello" };
        std::stringstream ss;
        msgpack::pack(ss, lm);
    
        msgpack::object obj = msgpack::unpack(ss.str().data(), ss.str().size()).get();
        logd::log_msg lm2 = obj.as<logd::log_msg>();
        assert(lm.level() == lm2.level());
        assert(lm.domain() == lm2.domain());
        assert(lm.message() == lm2.message());
    }
    

    【讨论】:

      【解决方案2】:

      似乎可行的一种方法是将枚举包装在一个联合中......

      union log_level_t {
          log_level lev;
          int       levint;
      }
      
      ...
      
          log_level_t lev_;
      
      ...
      
      MSGPACK_DEFINE(lev_.levint, dom_.domint, msg);
      

      这似乎是一种糟糕的方法,但它确实有效。

      【讨论】:

      • 这是将枚举类与 MessagePack 一起使用的唯一方法吗?没那么优雅!
      【解决方案3】:

      我找到了另一个解决方案,也许更优雅一点(好吧,它不是那么完美):

      MSGPACK_DEFINE((int&)lev_, (int&)dom_, msg)
      

      因此您可以保留原来的枚举而不创建新的联合。

      反序列化方法应该可以正常工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-09-11
        • 1970-01-01
        • 1970-01-01
        • 2010-12-31
        • 1970-01-01
        • 1970-01-01
        • 2012-10-09
        • 2021-12-24
        相关资源
        最近更新 更多