Cereal Polymorphic Serialization 找不到序列化函数

Cereal Polymorphic Serialization couldnt find serialization function

我目前正在尝试创建一个具有静态函数的 Base Class Serializable 来序列化和反序列化派生的 Class 对象。 我已经阅读了用于注册多态关系的谷物文档以及如何注册类型以及如何声明序列化函数。 目标是像这样使用 Serializable:

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

我正在使用 Visual Studio 平台工具 2017(v141)。目标 Windows SDK 是 10.0.17134.0

但我无法构建我的应用程序,并且 3 次出现这 2 个错误:

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 ==========

由于您正在尝试序列化 shared_ptr(),因此您应该包括 <cereal/types/memory.hpp>

Afaik,如果你想调用 cereal::base_class<Serializable>(this),那么基础 class 也需要一个 serialize(Archive& ar) 函数。由于没有理由在您的示例中序列化基础 class (没有成员变量),让我们将 TestObject serialize 简化为 ar(name);

那么您所缺少的只是 Serializable.cpp 中的 #include <cereal/types/polymorphic.hpp> 或更好的 #include <cereal/types/memory.hpp>。如 cereal 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