Можно ли воссоздать одну из функций десериализации Protobuf с помощью Cereal? - PullRequest
0 голосов
/ 07 июля 2019

Я могу написать код для десериализации прототипа сообщения, содержащего раздел oneof, без необходимости заранее знать, что содержится в разделе oneof.Я не могу понять, как написать подобный набор определений структуры, которые я могу десериализовать таким же образом, используя Cereal.

Я использовал Protobufs для сериализации / десериализации некоторых данных, но я столкнулся с тем жепроблема как piaoxu .Поэтому я перешел на использование Cereal.

Я смог преобразовать все исходные прото-определения в определения структур C ++, которые можно сериализовать с помощью Cereal, за исключением прототипов, которые используют функциональность oneof.

Вот пример набора прототипных определений, которые я хотел бы преобразовать в структуры:

syntax = "proto3";
package Messages;

message A {}

message B {}

message Message {
    oneof contents {
        A a = 1;
        B b = 2;
    }
}

Вот соответствующий код C ++, который я написал для десериализации и анализа полученного Message.Используя сгенерированный код 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, но AFAIK это невозможно.

Это действительно так?невозможно использовать мой текущий подход?И если так, есть ли другой подход, который позволит мне десериализовать подобный набор структур, не зная, что в нем содержится?

1 Ответ

0 голосов
/ 09 июля 2019

С помощью комментария Игоря я смог изменить структуру 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 переменную для десериализации данных в.

...