std :: string_view的自定义序列化会导致意外的编译器错误

时间:2019-05-05 12:26:26

标签: c++ c++17 cereal

我已经在github(大约一个月前)问了这个问题,没有任何答案,所以我现在在这里问。

我在项目中使用Cereal作为序列化库。我尝试为std::string_view添加序列化功能(基本上是从std::string实现中复制并粘贴)。但是,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 个答案:

答案 0 :(得分:2)

构建了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>,...>

使用它会更一致