Reputation: 159
I'm currently trying to create a Base Class Serializable with static functions to serialize and deserialize derived Class Objects. I've read the Cereal Documentation for registering Polymorphic Relations and how to register types and also how to declare serialization functions. The Goal is to use Serializable like this:
std::stringstream& ss Serializable::serialize(test);
I am using Visual Studio Platform Tools 2017(v141). The Target Windows SDK is 10.0.17134.0
But I cant build my application and get these 2 errors 3x:
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.
This is my Code:
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;
}
This is the complete building Error:
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 ==========
Upvotes: 1
Views: 1954
Reputation: 13134
Since you're trying to serialize a shared_ptr()
you should include <cereal/types/memory.hpp>
.
Upvotes: 0
Reputation: 11271
Afaik, If you want to call cereal::base_class<Serializable>(this)
, then the base class also needs a serialize(Archive& ar)
function. As there is no reason to serialize the base class in your example (no member variables), let's simplify the TestObject
serialize
to ar(name);
Then all you're missing is a #include <cereal/types/polymorphic.hpp>
or maybe better #include <cereal/types/memory.hpp>
in the Serializable.cpp. As described in the cereal Docs-Polymorphism, this include allows PortableBinary[Input/Output]Archive
to see the CEREAL_REGISTER_POLYMORPHIC_RELATION
that you set in your derivatives.
Example:
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;
}
Output:
Test
Upvotes: 1