我简化的人为(最小)示例。
第1步要使基本类型带有枚举的“种类”字段,该字段必须由派生的构造函数填充。请注意,由于非默认构造函数会初始化BodyPart,因此没有理由为其进行序列化。
我们确实必须有一个虚拟析构函数,因为我们将创建shared_ptr并将其传递给周围,并且我们要确保不执行切片〜BodyPart。
struct BodyPart
{
enum class Kind {
Head,
Shoulder,
Knee,
Toe,
};
BodyPart(Kind _kind) : kind(_kind) {}
Kind const kind;
virtual ~BodyPart() = default;
/* ---- Should never happen, but added to make Cereal happy that this can be in/out cerealized --- */
template<class Archive>
void serialize( Archive & ar )
{
(void)ar; assert(0);
}
template <class Archive>
static void load_and_construct( Archive & ar, cereal::construct<BodyPart> & construct )
{
(void)ar; (void)construct; assert(0);
}
/* ---- end make cereal happy --- */
};
步骤2,添加带有一些实际数据的派生类
struct Head : BodyPart
{
Head(int _eyeCount) : BodyPart(Kind::Head), eyeCount(_eyeCount) {}
int const eyeCount;
template<class Archive>
void serialize( Archive & ar )
{
ar( eyeCount );
}
template <class Archive>
static void load_and_construct( Archive & ar, cereal::construct<Head> & construct )
{
int x;
ar( x );
construct( x );
}
};
第3步,执行所需的注册
CEREAL_REGISTER_TYPE(Head)
CEREAL_REGISTER_POLYMORPHIC_RELATION(BodyPart, Head)
第4步,谷物化:
std::shared_ptr<BodyPart> head = std::make_shared<Head>(3);
std::string data;
{
std::ostringstream oss(std::ios::binary);
cereal::PortableBinaryOutputArchive oarchive(oss);
oarchive(head);
data = oss.str();
}
decltype(head) head2;
{
std::istringstream iss(data);
cereal::PortableBinaryInputArchive iarchive(iss);
iarchive(head2);
}
经过一段时间的讨论,似乎没有其他方法可以“说服”谷物,而我从来不想直接序列化(谷物化?)BodyPart。我找到了两个可行的解决方案
向基中添加一个虚拟纯虚函数,然后在所有派生类中对其进行定义。显然,这是愚蠢的,不是我要在实际代码中要做的事情。也与非侵入式方法不兼容。
Nicer版本1,创建一个额外的类来定义覆盖,以便不污染派生类。仍然很侵入。
执行上述操作,并为基类添加Cereal函数,并出现运行时错误(在实际代码中,我会抛出std :: logic_error或类似内容)。
我猜会很好的是:
[嘿,有时写出来使您相信答案,是吗? ]
无论如何,这是TLDR的方式,请阅读本文。请告诉我我是不是疯了,还是至少以明智的方式定义了“问题空间”。