std::string_view 的自定义序列化导致意外的编译器错误
Custom serialization of std::string_view causes unexpected compiler error
我已经在 github 上问过这个问题(大约一个月前),没有任何答案所以我现在在这里问。
我在项目中使用 Cereal 作为序列化库。我尝试为 std::string_view
添加序列化功能(基本上是从 std::string
实现中复制和粘贴)。但是,Cereal 会抛出一个编译器错误:
cereal could not find any output serialization functions for the provided type and archive combination.
这是我的实现(我在这里禁用了反序列化,但我也尝试了一个虚拟函数,它给了我相同的结果):
#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 存档会出现编译器错误?
由于 std::string
支持 JSON 和 XML 序列化程序是内置的,所以在 cereal/types/string.hpp
header.
中找不到
您必须像对二进制数据一样手动添加对字符串数据的支持。
我对谷物图书馆没有经验,但在文档中有 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>,...>
会更一致
我已经在 github 上问过这个问题(大约一个月前),没有任何答案所以我现在在这里问。
我在项目中使用 Cereal 作为序列化库。我尝试为 std::string_view
添加序列化功能(基本上是从 std::string
实现中复制和粘贴)。但是,Cereal 会抛出一个编译器错误:
cereal could not find any output serialization functions for the provided type and archive combination.
这是我的实现(我在这里禁用了反序列化,但我也尝试了一个虚拟函数,它给了我相同的结果):
#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 存档会出现编译器错误?
由于 std::string
支持 JSON 和 XML 序列化程序是内置的,所以在 cereal/types/string.hpp
header.
您必须像对二进制数据一样手动添加对字符串数据的支持。
我对谷物图书馆没有经验,但在文档中有 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>,...>