Pregunta

I am using the cereal library and am trying to get a shared_ptr instance of a derived type with a custom constructor to be fed into an archive correctly. I've poured over the following documentation but am clearly missing something.

Here are the classes in my heirarchy:

class TextureDefinition : public std::enable_shared_from_this<TextureDefinition> {
    template <class Archive>
    friend void serialize(Archive & archive, TextureDefinition & texture);
public:
    virtual ~TextureDefinition(){}
    std::shared_ptr<TextureHandle> makeHandle();
    std::shared_ptr<TextureHandle> makeHandle(const Point<int> &a_position, const Size<int> &a_size);

    void setOnReload(std::function< void (std::shared_ptr<TextureDefinition>) > a_onReload);
    void clearOnReload();

    GLuint textureId() const;
    std::string name() const;
    Size<int> size() const;

    //bookkeeping
    void reload();
    void cleanup();

protected:
    TextureDefinition(const std::string &a_name);

    std::string textureName;
    Size<int> textureSize;
    GLuint texture;

    std::vector< std::weak_ptr<TextureHandle> > handles;

private:
    virtual void reloadImplementation() = 0;
    virtual void cleanupImplementation(){}

    std::function< void (std::shared_ptr<TextureDefinition>) > onReload;
};

template <class Archive>
void serialize(Archive & archive, TextureDefinition &texture){
    archive(cereal::make_nvp("name", texture.name()), cereal::make_nvp("size", texture.size()));// , cereal::make_nvp("handles", handles)); //not saving handles right now to simplify testing.
}

class FileTextureDefinition : public TextureDefinition {
public:
    static std::shared_ptr<FileTextureDefinition> make(const std::string &a_filename, bool a_repeat = false){
        return std::shared_ptr<FileTextureDefinition>(new FileTextureDefinition(a_filename, a_repeat));
    }

    template <class Archive>
    static FileTextureDefinition * load_and_allocate(Archive &ar){
        return new FileTextureDefinition("", false);
    }

    template <class Archive>
    void serialize(Archive & archive){
        archive(cereal::base_class<TextureDefinition>(this), CEREAL_NVP(repeat));
        if(!handles.empty()){
            reload();
        }
    }
private:
    FileTextureDefinition(const std::string &a_filename, bool a_repeat):
        TextureDefinition(a_filename),
        repeat(a_repeat){
    }
    virtual void reloadImplementation();

    bool repeat;
};

And this is the test code I'm trying to get to run:

void saveTest(){
    std::stringstream stream;
    {
        cereal::JSONOutputArchive archive(stream);
        auto testSave = MV::FileTextureDefinition::make("test.png");
        archive(cereal::make_nvp("test", testSave));
    }
    std::cout << stream.str() << std::endl;
}

My "Size" type does serialize correctly. I am also including cereal/types/memory.hpp, cereal/types/map.hpp, cereal/types/string.hpp, and cereal/types/base_class.hpp, but when I try to run the test above for FileTextureDefinition I get the following error:

1>C:\git\external\cereal\include\cereal/cereal.hpp(432): error C2338: Trying to serialize an unserializable type with an output archive.
1>  
1>  Types must either have a serialize function, or separate save/load functions (but not both). 
1>  In addition, you may not mix versioned with non-versioned serialization functions. 
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>          C:\git\external\cereal\include\cereal/cereal.hpp(329) : see reference to function template instantiation 'cereal::JSONOutputArchive &cereal::OutputArchive<cereal::JSONOutputArchive,0>::processImpl<std::shared_ptr<MV::FileTextureDefinition>>(const T &)' being compiled
1>          with
1>          [
1>              T=std::shared_ptr<MV::FileTextureDefinition>
1>          ]
1>          C:\git\external\cereal\include\cereal/cereal.hpp(329) : see reference to function template instantiation 'cereal::JSONOutputArchive &cereal::OutputArchive<cereal::JSONOutputArchive,0>::processImpl<std::shared_ptr<MV::FileTextureDefinition>>(const T &)' being compiled
1>          with
1>          [
1>              T=std::shared_ptr<MV::FileTextureDefinition>
1>          ]
1>          C:\git\external\cereal\include\cereal/cereal.hpp(245) : see reference to function template instantiation 'void cereal::OutputArchive<cereal::JSONOutputArchive,0>::process<std::shared_ptr<MV::FileTextureDefinition>&>(T)' being compiled
1>          with
1>          [
1>              T=std::shared_ptr<MV::FileTextureDefinition> &
1>          ]
1>          C:\git\external\cereal\include\cereal/cereal.hpp(245) : see reference to function template instantiation 'void cereal::OutputArchive<cereal::JSONOutputArchive,0>::process<std::shared_ptr<MV::FileTextureDefinition>&>(T)' being compiled
1>          with
1>          [
1>              T=std::shared_ptr<MV::FileTextureDefinition> &
1>          ]
1>          C:\git\external\cereal\include\cereal/archives/json.hpp(711) : see reference to function template instantiation 'ArchiveType &cereal::OutputArchive<ArchiveType,0>::operator ()<_Ty&>(_Ty &)' being compiled
1>          with
1>          [
1>              ArchiveType=cereal::JSONOutputArchive
1>  ,            _Ty=std::shared_ptr<MV::FileTextureDefinition>
1>          ]
1>          C:\git\external\cereal\include\cereal/archives/json.hpp(711) : see reference to function template instantiation 'ArchiveType &cereal::OutputArchive<ArchiveType,0>::operator ()<_Ty&>(_Ty &)' being compiled
1>          with
1>          [
1>              ArchiveType=cereal::JSONOutputArchive
1>  ,            _Ty=std::shared_ptr<MV::FileTextureDefinition>
1>          ]
1>          C:\git\external\cereal\include\cereal/cereal.hpp(404) : see reference to function template instantiation 'void cereal::save<std::shared_ptr<MV::FileTextureDefinition>&>(cereal::JSONOutputArchive &,const cereal::NameValuePair<std::shared_ptr<MV::FileTextureDefinition> &> &)' being compiled
1>          C:\git\external\cereal\include\cereal/cereal.hpp(329) : see reference to function template instantiation 'cereal::JSONOutputArchive &cereal::OutputArchive<cereal::JSONOutputArchive,0>::processImpl<T>(const T &)' being compiled
1>          with
1>          [
1>              T=cereal::NameValuePair<std::shared_ptr<MV::FileTextureDefinition> &>
1>          ]
1>          C:\git\external\cereal\include\cereal/cereal.hpp(329) : see reference to function template instantiation 'cereal::JSONOutputArchive &cereal::OutputArchive<cereal::JSONOutputArchive,0>::processImpl<T>(const T &)' being compiled
1>          with
1>          [
1>              T=cereal::NameValuePair<std::shared_ptr<MV::FileTextureDefinition> &>
1>          ]
1>          C:\git\external\cereal\include\cereal/cereal.hpp(245) : see reference to function template instantiation 'void cereal::OutputArchive<cereal::JSONOutputArchive,0>::process<_Ty>(T &&)' being compiled
1>          with
1>          [
1>              _Ty=cereal::NameValuePair<std::shared_ptr<MV::FileTextureDefinition> &>
1>  ,            T=cereal::NameValuePair<std::shared_ptr<MV::FileTextureDefinition> &>
1>          ]
1>          C:\git\external\cereal\include\cereal/cereal.hpp(245) : see reference to function template instantiation 'void cereal::OutputArchive<cereal::JSONOutputArchive,0>::process<_Ty>(T &&)' being compiled
1>          with
1>          [
1>              _Ty=cereal::NameValuePair<std::shared_ptr<MV::FileTextureDefinition> &>
1>  ,            T=cereal::NameValuePair<std::shared_ptr<MV::FileTextureDefinition> &>
1>          ]
1>          c:\git\wargameclient\source\game.h(49) : see reference to function template instantiation 'ArchiveType &cereal::OutputArchive<ArchiveType,0>::operator ()<cereal::NameValuePair<std::shared_ptr<MV::FileTextureDefinition> &>>(cereal::NameValuePair<std::shared_ptr<MV::FileTextureDefinition> &> &&)' being compiled
1>          with
1>          [
1>              ArchiveType=cereal::JSONOutputArchive
1>          ]
1>          c:\git\wargameclient\source\game.h(49) : see reference to function template instantiation 'ArchiveType &cereal::OutputArchive<ArchiveType,0>::operator ()<cereal::NameValuePair<std::shared_ptr<MV::FileTextureDefinition> &>>(cereal::NameValuePair<std::shared_ptr<MV::FileTextureDefinition> &> &&)' being compiled
1>          with
1>          [
1>              ArchiveType=cereal::JSONOutputArchive
1>          ]

A full link of the textures.h header file can be found here on pastebin, but I have included what I believe are the relevant sections.

¿Fue útil?

Solución

Ah-hah! So the issue was pretty simple. I'm used to polymorphism being kind of automatically dealt with, but with Cereal you must register your types specifically. This was solved for me by adding the following three lines to my textures.cpp file and including "cereal/types/polymorphic.hpp":

CEREAL_REGISTER_TYPE(MV::FileTextureDefinition);
CEREAL_REGISTER_TYPE(MV::DynamicTextureDefinition);
CEREAL_REGISTER_TYPE(MV::SurfaceTextureDefinition);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top