我能够编写代码来反序列化包含oneof节的原始消息,而无需事先知道oneof节包含什么。我无法弄清楚如何编写一组相似的结构定义,我可以使用Cereal以相同的方式反序列化。
我当时使用Protobufs序列化/反序列化某些数据,但是遇到了the same problem as piaoxu。所以我改用谷物食品。
除了使用oneof功能的原型定义之外,我已经能够将所有原始原型定义转换为可以使用Cereal进行序列化的C ++结构定义。
这是一组我想转换为结构的原型定义的示例:
syntax = "proto3";
package Messages;
message A {}
message B {}
message Message {
oneof contents {
A a = 1;
B b = 2;
}
}
这是我编写的用于反序列化和解析收到的Message
的相应C ++代码。使用生成的protobuf代码,我可以对Message
进行反序列化,而无需先知道它是否包含A
或B
:
void ParseData(const string& data) {
{
auto message = new Messages::Message();
message->ParseFromString(data);
switch (message->contents_case()) {
case Messages::Message::kA:
std::cout << "I got an A!" << std::endl;
break;
case Messages::Message::kB:
std::cout << "I got a B!" << std::endl;
break;
default:
break;
}
}
这是我尝试制作一组等效的结构定义的方法:
struct A {};
struct B {};
template <class Contents>
struct Message {
enum Type {
A,
B,
};
Type type;
Contents contents;
template <class Archive>
void serialize(Archive& archive) {
archive(type, contents);
}
};
我正在使用这些结构来序列化并发送如下消息:
bool SendA() {
Message<A> message{};
ostringstream stream;
message.type = Message::Type::A;
message.contents = new A{};
{
cereal::PortableBinaryOutputArchive archive(stream);
archive(message);
}
return SendData(stream.str());
}
在我尝试反序列化收到的Message
之前,此方法一直有效。我希望能够在不知道它包含Message
或A
的情况下反序列化B
,但这是不可能的。 >
使用我当前的方法确实不可能吗?如果是这样,还有另一种方法可以让我在不首先知道其包含的内容的情况下反序列化一组相似的结构吗?
答案 0 :(得分:0)
借助Igor's comment,我可以将Message
结构更改为可反序列化的方式,而无需先知道其包含的内容:
struct A {};
struct B {};
struct Message {
enum Type {
A,
B,
};
Type type;
unique_ptr<::A> a = nullptr;
unique_ptr<::B> b = nullptr;
template <class Archive>
void serialize(Archive& archive) {
archive(type, contents);
}
};
诀窍是不要使Message
结构成为模板。
我写Message
结构的第一种方法是包括模板成员变量contents
,用于存储每个可能的内部结构(A
或B
)。这要求您先了解序列化的Message
结构包含的内容 ,然后才能对它进行反序列化,因为必须首先创建专用的Message
变量才能对数据进行反序列化。
相反,您可以为每个可能的内部数据结构创建一个unique_ptr
。这样一来,您就可以创建未模板化的Message
结构,也不必创建专门的Message
变量即可将数据反序列化。