我减少了一个人为的(最小的)示例。
第 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。我找到了两个可行的解决方案
在基类中添加一个伪纯虚函数,然后在所有派生类中定义它。显然这是愚蠢的,而不是我要在真实代码中做的事情。也不兼容非侵入式方法。
更好的版本 1,创建一个额外的类来定义覆盖,这样它就不会污染派生类。仍然非常具有侵入性。
做我上面做的事情,并为基类添加运行时错误的 Cereal 函数(在实际代码中,我会抛出 std::logic_error 或其他东西)。
我想最好的是:
Cereal 神奇地做了正确的事情,并推迟寻找基类序列化函数,直到我实际序列化它。这是不可能的,因为反序列化的翻译单元对序列化的内容一无所知(可能在任何地方)。必须以某种方式将这些知识注入到输出存档中。
[ 呵呵,有时候写出来会让你相信答案,嗯?]
- 一种强制 Cereal 将类视为抽象基类的显式方法,即使它不是。查看 polymorphic.hpp,很少有使用 std::is_abstract 的地方。可以(?)添加一个谷物::is_abstract 类型特征,客户可以使用它来注入一个类永远不会直接反序列化的知识。
无论如何,这是 TLDR 的方式,感谢您阅读到这里。请告诉我我是不是疯了,或者我是否至少以一种明智的方式定义了“问题空间”。