сериализация — MessagePack, c ++: как использовать MSGPACK_DEFINE с перечисляемыми классами c ++ 11

Следующий образец не компилируется, жалуясь, что

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

и соответствующая ошибка для другого класса enum. Мой вопрос заключается в том, как с помощью API-интерфейса c ++ msgpack можно сериализовать класс с членами класса 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 счастливым. К сожалению, я не могу найти никаких ссылок на эту тему в своих документах или первых двух страницах Google. Я также не могу определить, что делать, читая их заголовки / исходники, так как я довольно новичок в c ++.

2

Решение

Вы можете использовать макрос 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);

Это похоже на дерьмовый подход, но он работает.

0

Я нашел другое решение, возможно, немного более элегантное (хорошо, оно не так идеально):

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

Таким образом, вы можете сохранить свое первоначальное перечисление, не создавая новый союз.

Метод десериализации должен работать без проблем.

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