Полиморфная сериализация зерновых не может найти функцию сериализации

В настоящее время я пытаюсь создать сериализуемый базовый класс со статическими функциями для сериализации и десериализации производных объектов класса. Я прочитал документацию Cereal для регистрации полиморфных отношений и того, как регистрировать типы, а также как объявлять функции сериализации. Цель состоит в том, чтобы использовать Serializable следующим образом:

std::stringstream& ss Serializable::serialize(test);

Я использую Visual Studio Platform Tools 2017(v141). Целевой Windows SDK - 10.0.17134.0

Но я не могу собрать свое приложение и получить эти 2 ошибки 3 раза:

Error   C2338   cereal could not find any output serialization functions for the provided type and archive combination.

Error   C2338   cereal could not find any input serialization functions for the provided type and archive combination.

Это мой код:

Serializable.hpp
#pragma once
#include <string>
#include <cereal/archives/portable_binary.hpp>

class Serializable 
{
public:
Serializable() = default;
~Serializable() = default;
    virtual bool isAccessible() = 0;

    static std::stringstream serialize(std::shared_ptr<Serializable> serializable);
    static std::shared_ptr<Serializable> deserialize(std::stringstream& serialized);
};
Serializable.cpp
#include "Serializable.hpp"

std::stringstream Serializable::serialize(std::shared_ptr<Serializable> serializable)
{
    std::stringstream ss;
    {
        cereal::PortableBinaryOutputArchive  ar(ss);
        ar << serializable;
    }
    return ss;
}

std::shared_ptr<Serializable> Serializable::deserialize(std::stringstream& serialized)
{
    cereal::PortableBinaryInputArchive ar(serialized);
    std::shared_ptr<Serializable> result = nullptr;
    ar >> result;
    return result;
}
TestObject.hpp
#pragma once
#include "Serializable.hpp"
#include <string>
#include <cereal/types/string.hpp>
#include <cereal/types/polymorphic.hpp>
#include <cereal/types/base_class.hpp>

class TestObject : public Serializable
{
public:
TestObject() = default;
TestObject(const std::string& name);
~TestObject() = default;
    std::string getName() const { return this->name; };



    template<class Archive>
    void serialize(Archive& ar)
    {
        ar(cereal::base_class<Serializable>(this), name);
    };

    virtual bool isAccessible() {
        return true;
    };

private:
    std::string name;
};

CEREAL_REGISTER_TYPE(TestObject)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Serializable,TestObject)
TestObject.cpp
#include "TestObject.hpp"
TestObject::TestObject(const std::string& name)
    :TestObject(name){}
main.cpp
#include "TestObject.hpp"
#include "Serializable.hpp"
#include <memory>
#include <iostream>
#include <string>

int main(int argc, char **argv)
{
    std::shared_ptr<Serializable> test(new TestObject("Test"));
    auto ss = Serializable::serialize(test);
    std::shared_ptr<Serializable> deserialized = Serializable::deserialize(ss);
    auto test2 = dynamic_cast<TestObject*>(deserialized.get());
    std::cout << test2->getName();
    system("timeout 3");
    return 0;
}

Это полная ошибка здания:

1>------ Build started: Project: SerializableTest, Configuration: Debug Win32 ------
1>TestObject.cpp
1>Serializable.cpp
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\lib\cereal\include\cereal\cereal.hpp(462): error C2338: cereal could not find any output serialization functions for the provided type and archive combination.
1>
1> Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these).
1> Serialize functions generally have the following signature:
1>
1> template<class Archive>
1>   void serialize(Archive & ar)
1>   {
1>     ar( member1, member2, member3 );
1>   }
1>
1>
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\lib\cereal\include\cereal\cereal.hpp(347): note: see reference to function template instantiation 'ArchiveType &cereal::OutputArchive<ArchiveType,1>::processImpl<std::shared_ptr<Serializable>,0>(const T &)' being compiled
1>        with
1>        [
1>            ArchiveType=cereal::PortableBinaryOutputArchive,
1>            T=std::shared_ptr<Serializable>
1>        ]
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\lib\cereal\include\cereal\cereal.hpp(347): note: see reference to function template instantiation 'ArchiveType &cereal::OutputArchive<ArchiveType,1>::processImpl<std::shared_ptr<Serializable>,0>(const T &)' being compiled
1>        with
1>        [
1>            ArchiveType=cereal::PortableBinaryOutputArchive,
1>            T=std::shared_ptr<Serializable>
1>        ]
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\lib\cereal\include\cereal\cereal.hpp(290): note: see reference to function template instantiation 'void cereal::OutputArchive<cereal::PortableBinaryOutputArchive,1>::process<std::shared_ptr<Serializable>&>(T)' being compiled
1>        with
1>        [
1>            T=std::shared_ptr<Serializable> &
1>        ]
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\lib\cereal\include\cereal\cereal.hpp(290): note: see reference to function template instantiation 'void cereal::OutputArchive<cereal::PortableBinaryOutputArchive,1>::process<std::shared_ptr<Serializable>&>(T)' being compiled
1>        with
1>        [
1>            T=std::shared_ptr<Serializable> &
1>        ]
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\serializable.cpp(8): note: see reference to function template instantiation 'ArchiveType &cereal::OutputArchive<ArchiveType,1>::operator <<<std::shared_ptr<Serializable>&>(T)' being compiled
1>        with
1>        [
1>            ArchiveType=cereal::PortableBinaryOutputArchive,
1>            T=std::shared_ptr<Serializable> &
1>        ]
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\serializable.cpp(8): note: see reference to function template instantiation 'ArchiveType &cereal::OutputArchive<ArchiveType,1>::operator <<<std::shared_ptr<Serializable>&>(T)' being compiled
1>        with
1>        [
1>            ArchiveType=cereal::PortableBinaryOutputArchive,
1>            T=std::shared_ptr<Serializable> &
1>        ]
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\lib\cereal\include\cereal\cereal.hpp(851): error C2338: cereal could not find any input serialization functions for the provided type and archive combination.
1>
1> Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these).
1> Serialize functions generally have the following signature:
1>
1> template<class Archive>
1>   void serialize(Archive & ar)
1>   {
1>     ar( member1, member2, member3 );
1>   }
1>
1>
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\lib\cereal\include\cereal\cereal.hpp(730): note: see reference to function template instantiation 'ArchiveType &cereal::InputArchive<ArchiveType,1>::processImpl<std::shared_ptr<Serializable>,0>(const T &)' being compiled
1>        with
1>        [
1>            ArchiveType=cereal::PortableBinaryInputArchive,
1>            T=std::shared_ptr<Serializable>
1>        ]
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\lib\cereal\include\cereal\cereal.hpp(730): note: see reference to function template instantiation 'ArchiveType &cereal::InputArchive<ArchiveType,1>::processImpl<std::shared_ptr<Serializable>,0>(const T &)' being compiled
1>        with
1>        [
1>            ArchiveType=cereal::PortableBinaryInputArchive,
1>            T=std::shared_ptr<Serializable>
1>        ]
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\lib\cereal\include\cereal\cereal.hpp(660): note: see reference to function template instantiation 'void cereal::InputArchive<cereal::PortableBinaryInputArchive,1>::process<std::shared_ptr<Serializable>&>(T)' being compiled
1>        with
1>        [
1>            T=std::shared_ptr<Serializable> &
1>        ]
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\lib\cereal\include\cereal\cereal.hpp(660): note: see reference to function template instantiation 'void cereal::InputArchive<cereal::PortableBinaryInputArchive,1>::process<std::shared_ptr<Serializable>&>(T)' being compiled
1>        with
1>        [
1>            T=std::shared_ptr<Serializable> &
1>        ]
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\serializable.cpp(17): note: see reference to function template instantiation 'ArchiveType &cereal::InputArchive<ArchiveType,1>::operator >><std::shared_ptr<Serializable>&>(T)' being compiled
1>        with
1>        [
1>            ArchiveType=cereal::PortableBinaryInputArchive,
1>            T=std::shared_ptr<Serializable> &
1>        ]
1>k:\programme\c++\serializabletest\networkdebugs\serializabletest\serializable.cpp(17): note: see reference to function template instantiation 'ArchiveType &cereal::InputArchive<ArchiveType,1>::operator >><std::shared_ptr<Serializable>&>(T)' being compiled
1>        with
1>        [
1>            ArchiveType=cereal::PortableBinaryInputArchive,
1>            T=std::shared_ptr<Serializable> &
1>        ]
1>main.cpp
1>Generating Code...
1>Done building project "SerializableTest.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

2 ответа

Решение

Афаик, если хочешь позвонить cereal::base_class<Serializable>(this)то базовому классу тоже нужен serialize(Archive& ar) функция. Поскольку в вашем примере нет причин сериализации базового класса (без переменных-членов), давайте упростим TestObjectserialize в ar(name);

Тогда все, что вам не хватает, это #include <cereal/types/polymorphic.hpp> а может лучше #include <cereal/types/memory.hpp> в Serializable.cpp. Как описано в Docs-Polymorphism, это включает в себя позволяет PortableBinary[Input/Output]Archive чтобы увидеть CEREAL_REGISTER_POLYMORPHIC_RELATION что вы установили в своих производных.

Пример:

Serializable.hpp

#pragma once
#include <sstream>
#include <memory>

class Serializable
{
public:
    Serializable() = default;
    virtual ~Serializable() = default;
    virtual bool isAccessible() = 0;

    static std::stringstream serialize(const std::shared_ptr<Serializable>& serializable);
    static std::shared_ptr<Serializable> deserialize(std::stringstream& serialized);
};

Serializable.cpp

#include "Serializable.hpp"
#include <cereal/archives/portable_binary.hpp>
#include <cereal/types/memory.hpp>

std::stringstream Serializable::serialize(const std::shared_ptr<Serializable>& serializable)
{
    std::stringstream ss;
    cereal::PortableBinaryOutputArchive ar(ss);
    ar(serializable);
    return ss;
}

std::shared_ptr<Serializable> Serializable::deserialize(std::stringstream& serialized)
{
    cereal::PortableBinaryInputArchive ar(serialized);
    std::shared_ptr<Serializable> result;
    ar(result);
    return result;
}

TestObject.hpp

#pragma once
#include "Serializable.hpp"
#include <string>
#include <cereal/types/polymorphic.hpp>

class TestObject : public Serializable
{
public:
    TestObject() = default;
    TestObject(const std::string& name) : name(name) {}
    ~TestObject() = default;
    std::string getName() const { return this->name; };

    template<class Archive>
    void serialize(Archive& ar)
    {
        ar(name);
    };

    bool isAccessible() override { return true; };
private:
    std::string name;
};

CEREAL_REGISTER_TYPE(TestObject);
CEREAL_REGISTER_POLYMORPHIC_RELATION(Serializable, TestObject)

main.cpp

#include "TestObject.hpp"
#include "Serializable.hpp"
#include <memory>
#include <sstream>
#include <iostream>

int main(int argc, char **argv)
{
    auto test = std::dynamic_pointer_cast<Serializable>(std::make_shared<TestObject>("Test"));
    auto ss = Serializable::serialize(test);
    auto deserialized = Serializable::deserialize(ss);
    auto test2 = std::dynamic_pointer_cast<TestObject>(deserialized);
    std::cout << test2->getName();

    return 0;
}

Выход:

Test

Так как вы пытаетесь сериализовать shared_ptr() Вы должны включить <cereal/types/memory.hpp>,

Другие вопросы по тегам