我正在处理一个将消息(请求和响应)作为结构进行传输的网络。为了实现这一目标,我转向了增强串行化,效果很好!但是,由于消息和响应的类型如此之多,很难在所有这些消息和响应中都包含序列化功能,是否存在为所有结构自动生成方法或至少一次公开每个成员变量的捷径?
示例:
#pragma once
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/serialization.hpp>
struct Test
{
public:
int a;
int b;
template<typename archive> void serialize(archive& ar, const unsigned version) {
ar & a;
ar & b;
}
};
我相信我已经回答了此yesterday:
struct Test {
int a,b;
template<typename Ar> void serialize(Ar& ar, unsigned) { ar & a & b; }
};
请注意,如果您还序列化一个自由函数(使用ADL查找):
struct Test {
int a,b;
};
template<typename Ar> void serialize(Ar& ar, Test& o, unsigned) {
ar & o.a & o.b;
}
因此您可以单独获得序列化代码。最后,如果您有一组预定义的存档,则序列化功能根本不需要是模板:
using OArchive = boost::archive::binary_oarchive;
using IArchive = boost::archive::binary_iarchive;
struct Test {
int a,b;
void serialize(OArchive& ar, ...) const { ar & a & b; }
void serialize(IArchive& ar, ...) { ar & a & b; }
};
当然,这会产生一些重复。我很乐意忽略带有可变变量的version参数,但是在翻转大小上,它更const
正确。
如果您的结构是二进制可序列化的,则将它们标记为:
或显式将它们视为blob:make_binary_object
-在这种情况下,您不需要任何序列化方法:
make_binary_object
Live On Coliru
打印
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/binary_object.hpp>
#include <iostream>
using boost::serialization::make_binary_object;
struct Test { int a,b; };
int main() {
boost::archive::text_oarchive oa(std::cout, boost::archive::no_header);
Test req {13,31};
oa << make_binary_object(&req, sizeof(req));
}
公平警告,作为C程序员,您可能想纾困,而在这里只使用更多的预处理器魔术/代码生成器
说您有更多消息(可以嵌套):
DQAAAB8AAAA=
您可以将其改编为namespace Messages {
struct FooMsg { int a, b; };
struct BarMsg { std::string c; double d; };
struct QuxMsg { FooMsg e; BarMsg f; };
}
:
Fusion Sequences
好是现在您可以跨这些序列编写通用代码,所以让我们介绍我们自己的BOOST_FUSION_ADAPT_STRUCT(Messages::FooMsg, a, b)
BOOST_FUSION_ADAPT_STRUCT(Messages::BarMsg, c, d)
BOOST_FUSION_ADAPT_STRUCT(Messages::QuxMsg, e, f)
:
serialization wrapper
现在您可以对任何包装的消息实施序列化:
namespace Messages {
template <typename T>
struct MsgSerializationWrapper {
T& ref;
};
template <typename T>
static inline MsgSerializationWrapper<T> wrap(T& msg) { return {msg}; }
当然,我们需要一些检查来检测何时包装的类型不是融合序列,并以常规方式序列化该序列。
template <typename Ar, typename Msg>
void serialize(Ar& ar, MsgSerializationWrapper<Msg> wrapped, unsigned) {
boost::fusion::for_each(wrapped.ref, [&ar](auto& field) { ar & wrap(field); });
}
Live On Coliru
打印
#include <boost/archive/text_oarchive.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <iostream>
namespace Messages {
struct FooMsg { int a, b; };
struct BarMsg { std::string c; double d; };
struct QuxMsg { FooMsg e; BarMsg f; };
}
BOOST_FUSION_ADAPT_STRUCT(Messages::FooMsg, a, b)
BOOST_FUSION_ADAPT_STRUCT(Messages::BarMsg, c, d)
BOOST_FUSION_ADAPT_STRUCT(Messages::QuxMsg, e, f)
namespace Messages {
template <typename T>
struct MsgSerializationWrapper {
T& ref;
};
template <typename T>
static inline MsgSerializationWrapper<T> wrap(T& msg) { return {msg}; }
template <typename Ar, typename Msg>
std::enable_if_t<boost::fusion::traits::is_sequence<Msg>::value>
serialize(Ar& ar, MsgSerializationWrapper<Msg> wrapped, unsigned) {
boost::fusion::for_each(wrapped.ref, [&ar](auto& field) { ar & wrap(field); });
}
template <typename Ar, typename Primitive>
std::enable_if_t<not boost::fusion::traits::is_sequence<Primitive>::value>
serialize(Ar& ar, MsgSerializationWrapper<Primitive> wrapped, unsigned) {
ar & wrapped.ref;
}
}
int main() {
boost::archive::text_oarchive oa(std::cout);
Messages::QuxMsg req {
Messages::FooMsg { 42, 99 },
Messages::BarMsg { "hello world\n", 3.14e100 },
};
oa << wrap(req);
}