C++ Cereal save/load_and_construct не работает

Поэтому я пытаюсь использовать библиотеку Cereal и столкнулся с проблемой, которую, похоже, не могу решить. По сути, в документе говорится, что можно десериализовать типы без конструктора по умолчанию. Тем не менее, в заметках по реализации говорится Define a serialize or save/load pair as you normally would все же параметры сериализации / загрузки не могут быть определены корректным образом, если нет конструктора по умолчанию. Я так понимаю, что load_and_construct функция занимает место load, Еще при реализации сравнительно простого примера видно ниже.

"Main.cpp"

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <memory>

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

struct string_wrapper {
    const std::string str;

    string_wrapper(const std::string& _a) : str{_a} {}

    template <class Archive>
    void save(Archive& _archive) const {
        _archive(str);
    }

    template <class Archive>
    static void load_and_construct(Archive& _archive,
        cereal::construct<string_wrapper>& _construct) {
        std::string a;
        _archive(a);
        _construct(a);
    }
};

struct wrapper_of_string_wrappers {
    const std::vector<string_wrapper> strs;

    wrapper_of_string_wrappers(
        const std::vector<string_wrapper>& _a
    ) : strs{_a} { }

    template <class Archive>
    void save(Archive& _archive) const {
        _archive(strs);
    }

    template <class Archive>
    static void load_and_construct(Archive& _archive,
        cereal::construct<wrapper_of_string_wrappers>& _construct) {
        std::vector<string_wrapper> strs;
        _archive(strs);
        _construct(strs);
    }
};


int main() {

    auto file = "test.bin";

    { // save
        std::ofstream os(file, std::ios::binary);
        cereal::PortableBinaryOutputArchive archiveSave(os);

        std::vector<string_wrapper> as;
        as.push_back({"Hello"});
        as.push_back({"World"});

        wrapper_of_string_wrappers test(as);

        auto test_ptr = std::make_unique<wrapper_of_string_wrappers>(test);
        archiveSave(test_ptr);
    }

    { // load
        std::ifstream is(file, std::ios::binary);
        cereal::PortableBinaryInputArchive archiveLoad(is);

        std::unique_ptr<wrapper_of_string_wrappers> test = nullptr;
        archiveLoad(test);
        std::cout << (*test).strs[0].str << " " << (*test).strs[1].str << std::endl;
    }

    std::cin.get();

    return 0;
}

Этот код явно бессмысленен, это лишь минимальный пример, иллюстрирующий проблему, с которой я сталкиваюсь.

1 ответ

Решение

С этой страницы

Нестандартные конструкторы в настоящее время поддерживаются только для сериализации указателей

Ваша проблема здесь в том, что вы пытаетесь сериализовать не указатель значения без конструктора по умолчанию здесь

std::vector<string_wrapper> strs;
_archive(strs);

Чтобы решить вашу проблему, вам нужно сделать конструктор по умолчанию для string_wrapper с save/load пара или использование string_wrapper как указатель в wrapper_of_string_wrappers,

Вот рабочий код для второго варианта (string_wrapper остается таким же)

struct wrapper_of_string_wrappers {
    //const std::vector<std::unique_ptr<string_wrapper>> strs;
    //const string_wrapper strs;
    const std::unique_ptr<string_wrapper> strs;

    wrapper_of_string_wrappers(
        //const std::vector<std::unique_ptr<string_wrapper>>& _a
        const string_wrapper _a
    ) : strs{ new string_wrapper(_a) } { }

    wrapper_of_string_wrappers(
        const wrapper_of_string_wrappers& w
    ) : strs{ new string_wrapper(*w.strs) } { }

    template <class Archive>
    void save(Archive& _archive) const {
        _archive(strs);
    }

    template <class Archive>
    static void load_and_construct(Archive& _archive,
        cereal::construct<wrapper_of_string_wrappers>& _construct) {
        //std::vector<std::unique_ptr<string_wrapper>> strs;
        std::unique_ptr<string_wrapper> strs;
        _archive(strs);
        _construct(*strs);
    }
};

int main() {

    auto file = "test.bin";
    { // save
        std::ofstream os(file, std::ios::binary);
        cereal::PortableBinaryOutputArchive archiveSave(os);

        string_wrapper as("Hello");
        wrapper_of_string_wrappers test(as);

        auto test_ptr = std::make_unique<wrapper_of_string_wrappers>(test);
        archiveSave(test_ptr);
    }

    { // load
        std::ifstream is(file, std::ios::binary);
        cereal::PortableBinaryInputArchive archiveLoad(is);
        std::unique_ptr<wrapper_of_string_wrappers> test = nullptr;
        archiveLoad(test);
        std::cout << (*test).strs->str << std::endl;
    }

    std::cin.get();

    return 0;
} 
Другие вопросы по тегам