0

I am using the cereal library to serialize stuff. I am trying to serialize a class member of type std::vector with struct{ some unsingned short ints }.

This fails with the compiler message /usr/include/cereal/cereal.hpp:543: error: static assertion failed: cereal could not find any output serialization functions for the provided type and archive combination.

Replacing the data to be archived with an std::vector of unsigned short ints directly works as expected. Can somebody tell what I am doing wrong or if cereal is even capable of doing this with structs? I don't get it, because int's of any kind are evidently supported and vectors are too after adding the appropriate include. Just wrapping the ints in a struct does not work?

Simplified data class with stuff to be serialized: database.h

#include <utils/x_precompiled_headers.h>
#include <utils/serialize.h>
#include <database/datamodel.h>

class Database : public QObject
{
    Q_OBJECT

private:
    std::vector<Datamodel::model> models_;
    // std::vector<unsigned short int> test = {1,2,3};

void Database::SaveToDisk(){
    Serialize::ExportData(*this, "database");
}

void Database::LoadFromDisk(){
    Serialize::ImportData(*this, "database");
}

    // serialization
    friend class cereal::access;
    template<class Archive>
    void save(Archive &ar) const {
//                                   ar(test); // this does not complain
                                   ar(models_); //this gives the compiler error
                                 }
};

Definition header of the struct that I want to serialze: database/datamodel.h

namespace Datamodel
{
    typedef struct{
        unsigned short int number1;
        unsigned short int number2;

        template<class Archive>
        void save(Archive &ar) const{
            ar(number1, number2);
        }

        template<class Archive>
        void load(Archive &ar) const{
            ar(number1, number2);
        }
    } model;
}

Serialization class: utils/serialize.h

class Serialize
{
public:
    template<typename T>
    static void ExportData(T &object, const std::string &filename)
    {
        std::string path = std::filesystem::current_path() /= filename;
        std::ofstream ofs(path);

        if(ofs.is_open()){
            cereal::BinaryOutputArchive oarchive(ofs);
            oarchive(object);
            ofs.close();
        }
    }

    template <typename T>
    static void ImportData(T &object, const std::string &filename)
    {
        std::string path = std::filesystem::current_path() /= filename;

        if(!std::filesystem::exists(path))
            return;

        std::ifstream ifs(path);

        if(ifs.is_open())
        {
            cereal::BinaryInputArchive iarchive(ifs);
            iarchive(object);
            ifs.close();
        }
    }
};

Precompiled headers file, containing relevant includes: x_precompiled_headers.h

#include <cereal/access.hpp>
#include <cereal/archives/binary.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/vector.hpp>

Update 1: Okay, I have now updated the code and provided my struct with serialization methods. I have updated the code in th OP to reflect the changes. I have also included the save and load functions that I use in the database.h in the OP. Sadly it sill gives me this compiler error (/usr/include/cereal/cereal.hpp:822: error: no matching function for call to ‘cereal::BinaryInputArchive::processImpl(const std::vectorDatamodel::model&)’).

2 Answers2

1

Cereal knows how to serialize standard types such as vectors and ints out of the box, but not how to serialize Datamodel::model.

It also does not know out of the box how to serialize Database, but you told it how to with save

// serialization
    friend class cereal::access;
    template<class Archive>
    void save(Archive &ar) const {
//                                   ar(test); // this does not complain
                                   ar(models_); //this gives the compiler error
                                 }

You need to provide a similar implementation for Datamodel::model.

// serialization
friend class cereal::access;
template<class Archive>
void save(Archive &ar) const {
    ar(number1); 
    ar(number2); 
}
Jan15
  • 499
  • 3
  • 11
  • Okay, I'll try that. Thanks for your help! –  Jul 01 '21 at 17:44
  • Okay, I have now updated the code and provided my struct with serialization methods. I have updated the code in th OP to reflect the changes. I have also included the save and load functions that I use in the database.h. Sadly it sill gives me this compiler error (/usr/include/cereal/cereal.hpp:822: error: no matching function for call to ‘cereal::BinaryInputArchive::processImpl(const std::vector&)’) . Can I do anything to help you help me? I.e. commit my non-compiling code to Github? Or pastbin the whole compiler message? –  Jul 06 '21 at 18:24
  • @guttural you actually supposed to post code and error message here, see FAQ – Swift - Friday Pie Jul 07 '21 at 06:59
  • I did. I also posted the solution. –  Jul 08 '21 at 12:16
0

Solution: the load function (when you split save and loads) cannot be const. When splitting save and load templated functions, this is the correct scheme, also specified in the serialization function specification on cereal's website (https://uscilab.github.io/cereal/serialization_functions.html):

template<class Archive>
void save(Archive &ar) const{
    ar(models_);
}
template<class Archive>
void load(Archive &ar){
    ar(models_);
}