【问题标题】:Custom serialization of std::string_view causes unexpected compiler errorstd::string_view 的自定义序列化导致意外的编译器错误
【发布时间】:2019-05-05 12:26:26
【问题描述】:

我已经在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&lt;BinaryData&lt;CharT&gt;, Archive&gt; 中的特征有关,但该特征也存在于std::string 实现中并且工作得很好。我也找不到std::string 的第二个定义或专业化。

为什么我会收到 XML 和 JSON 档案的编译器错误?

【问题讨论】:

  • 我从未使用过这个库,但让我猜一下。您仅为二进制数据添加了序列化程序,但 JSON/XML 并非旨在存储二进制数据,并且很可能需要一些字符串 (char*?) 数据序列化程序。必须有一些通用的save 重载来处理您丢失的字符串数据。所以 trait is_output_serializable&lt;BinaryData&lt;CharT&gt;, Archive&gt; 按预期工作,您必须为 StringData trait 提供一个(如果存在)。
  • 天真地浏览 JSON 存档代码表明它已内置支持 std::string: github.com/USCiLab/cereal/blob/…
  • 抱歉这么多cmets,不能再编辑了。第 946 行定义了内置的 std::string 支持:github.com/USCiLab/cereal/blob/…
  • @R2RT 很好,我没有检查存档实现。如果您将您的 cmets 包装在一个答案中,我将很乐意接受它。
  • 完成。如果示例代码编译,请告诉我,我没有检查它的环境。

标签: c++ c++17 cereal


【解决方案1】:

由于 std::string 已构建对 JSON 和 XML 序列化程序的支持,因此无法在 cereal/types/string.hpp 标头中找到它。

您必须像对二进制数据一样手动添加对字符串数据的支持。

我在谷物图书馆方面没有经验,但在文档中有 std::map&lt;std::string, std::string&gt; 的存档专业化示例: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&lt;cereal::traits::is_text_archive&lt;Archive&gt;::value&gt; 来指定二进制输出特化。用它代替is_output_serializable&lt;BinaryData&lt;CharT&gt;,...&gt;会更一致

【讨论】:

    猜你喜欢
    • 2016-04-15
    • 1970-01-01
    • 2013-02-01
    • 2013-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多