Using Cereal to serialize templated polymorphic types in a library
Asked Answered
O

1

6

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?

Occlusive answered 20/10, 2016 at 12:47 Comment(5)
Sorry, transcription error, missed the <T>.Occlusive
The types in your examples don't seem to be polymorphic... are they actually representative of your real code? If so, that is an odd errorAcademicism
Have you followed the documentation? Have you used CEREAL_REGISTER_POLYMORPHIC_RELATION (if it's needed; I'm totally unfamiliar with cereal)? I agree with xaxxon that the code you posted isn't polymorphic.Heavily
According to the docs CEREAL_REGISTER_POLYMORPHIC_RELATION is only required if the subclass does not call the base class with cereal::base_class. Which I am doing.Occlusive
Updated to show polymorphic usage.Occlusive
O
6

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.

Occlusive answered 20/10, 2016 at 17:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.