Пользовательская сериализация std :: string_view вызывает неожиданную ошибку компилятора - PullRequest
5 голосов
/ 05 мая 2019

Я уже задавал этот вопрос на github (около месяца назад), без какого-либо ответа, поэтому я спрашиваю здесь и сейчас.

Я использую Cereal как библиотеку сериализации в моем проекте. Я попытался добавить функциональность сериализации для std::string_view (это в основном копирование и вставка из реализации std::string). Однако Cereal выдает ошибку компилятора:

cereal не смог найти никаких выходных функций сериализации для предоставленной комбинации типа и архива.

Вот моя реализация (здесь я отключил десериализацию, но я также попробовал фиктивную функцию, которая дала мне тот же результат):

#pragma once

#include "../cereal.hpp"

#include <string_view>

namespace cereal
{
    //! Serialization for basic_string_view types, if binary data is supported
    template <class Archive, class CharT, class Traits>
    typename std::enable_if<traits::is_output_serializable<BinaryData<CharT>, Archive>::value, void>::type
    CEREAL_SAVE_FUNCTION_NAME(Archive& ar, std::basic_string_view<CharT, Traits> const& str)
    {
        // Save number of chars + the data
        ar(make_size_tag(static_cast<size_type>(str.size())));
        ar(binary_data(str.data(), str.size() * sizeof(CharT)));
    }


    //! Deserialization into std::basic_string_view is forbidden due to its properties as a view.
    //! However std::basic_string_view can be deserialized into a std::basic_string.
    // template <class Archive, class CharT, class Traits>
    // void CEREAL_LOAD_FUNCTION_NAME(Archive& ar, std::basic_string_view<CharT, Traits> & str);
}

Минимальный пример:

#include <iostream>
#include <cereal/string_view>  

int main() 
{
    /*
     * Working archive types are:
     *  - BinaryOutputArchive
     *  - PortableBinaryOutputArchive
     *
     * Compiler errors for:
     *  - JSONOutputArchive
     *  - XMLOutputArchive
     */
    using OutputArchive = cereal::JSONOutputArchive;

    std::string_view str = "Hello World!";

    {
        OutputArchive oar(std::cout);
        oar(str);
    }

    return 0;
}

Тест успешно компилируется и проходит для двоичных архивов, но не для сериализации XML и JSON.

Я предполагаю, что это как-то связано с чертой в enable_if условии is_output_serializable<BinaryData<CharT>, Archive>, но эта черта также присутствует в реализации std::string и отлично работает. Я также не смог найти второе определение или специализацию для std::string.

Почему я получаю эту ошибку компилятора для архивов XML и JSON?

1 Ответ

2 голосов
/ 06 мая 2019

Поскольку встроена поддержка std::string для JSON и сериализатора XML, ее нельзя найти в заголовке cereal/types/string.hpp.

Вы должны вручную добавить поддержку строковых данных, как вы это делали для двоичных данных.

У меня нет опыта работы с библиотекой зерновых, но в документации есть пример специализаций по архивам для std::map<std::string, std::string>: http://uscilab.github.io/cereal/archive_specialization.html

Он использует немного другую технику SFINAE и характерные черты злаков (is_text_archive, проверьте в нижней части той же статьи).

Учитывая, что для вашего кода это дает:

namespace cereal
{
template <class Archive, class CharT, class Traits,
            traits::EnableIf<traits::is_text_archive<Archive>::value> = traits::sfinae> inline
void save( Archive & ar, std::basic_string_view<CharT, Traits> const & str )
{
    /// ...
}
}

Примечание: документы используют cereal::traits::DisableIf<cereal::traits::is_text_archive<Archive>::value> для указания специализации двоичного вывода. Было бы более последовательно использовать его вместо is_output_serializable<BinaryData<CharT>,...>

...