Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Cereal to serialize templated polymorphic types in a library

I have a templated base class:

template<typename T>
class A {
    public:
    T a;

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

and a templated class that derives from it:

template<typename T>
class B : public A<T> {
    public:
    T b;

    template<class Archive>
    void serialize(Archive & ar) {
        ar(cereal::base_class<A<T>>(this));
        ar(b);
    }
};

It is used in another serialized class:

template<typename T>
class C {

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

    std::vector<std::shared_ptr<A<T>>> collection;
};

This code and the code that uses it is compiled into a static lib

From my understanding of the cereal docs I need to add

CEREAL_REGISTER_TYPE(A<double>)
CEREAL_REGISTER_TYPE(A<float>)

CEREAL_REGISTER_TYPE(B<double>)
CEREAL_REGISTER_TYPE(B<float>)

etc for each type that will be used, in the header files for each class

This compiles. But has a run time error of

Trying to save an unregistered polymorphic type (B). Make sure your type is registered with CEREAL_REGISTER_TYPE and that the archive you are using was included (and registered with CEREAL_REGISTER_ARCHIVE) prior to calling CEREAL_REGISTER_TYPE. If your type is already registered and you still see this error, you may need to use CEREAL_REGISTER_DYNAMIC_INIT.

From the docs I think I need to add CEREAL_FORCE_DYNAMIC_INIT(libname) in the headers and CEREAL_REGISTER_DYNAMIC_INIT in the CPP file, but there is no cpp file. Or a suitable CPP file to place this in.

Adding CEREAL_REGISTER_POLYMORPHIC_RELATION makes no difference as expected as B's serialization function is calling the base calss A with cereal::base_class Is there a way to use Cereal to serialize templated classes?

like image 927
addicted2oxygen Avatar asked Oct 20 '16 12:10

addicted2oxygen


1 Answers

Issue came down to the order of the included headers and where they were included, plus a small amount of RTFM carefully.

In base class header needed:

#include <cereal/types/polymorphic.hpp>
#include <cereal/archives/portable_binary.hpp>

plus any other types I want to serialize to.

Then in subclasses add CEREAL_REGISTER_TYPE for each supported type.

The key, as noted in the documentation, is that the type of archive is included BEFORE CEREAL_REGISTER_TYPE. They do not have to be in the same file as the class declaration. Just include headers before registering types.

like image 126
addicted2oxygen Avatar answered Sep 25 '22 02:09

addicted2oxygen