【发布时间】:2016-09-23 05:55:04
【问题描述】:
在实现 C++1z 的 std::basic_string_view 以在较旧的编译器上使用它时,我遇到了 stream output operator overload 的问题。
基本上,它必须输出 string_view 引用的内容,同时不依赖任何空终止符存在(因为 string_view 不保证是空终止的)。
通常,为operator<< 编写重载非常容易,因为您可以依赖已经存在的重载,因此不需要使用哨兵对象as mentioned in this question on SO。
但在这种情况下,operator<< 没有预定义的重载,采用字符指针和长度 (obviously)。因此,我在当前的实现中创建了一个临时的 std::string 实例:
template< typename TChar, typename TTraits >
auto operator<<(::std::basic_ostream<TChar, TTraits>& p_os, basic_string_view<TChar, TTraits> p_v)
-> ::std::basic_ostream<TChar, TTraits>&
{
p_os << p_v.to_string(); // to_string() returns a ::std::string.
return p_os;
}
这可行,但我真的不喜欢我必须创建一个临时的 std::string 实例,因为这需要冗余复制数据和可能动态使用记忆。至少在我看来,这违背了使用轻量级引用类型的目的。
所以我的问题是:
在没有开销的情况下为我的 string_view 实现正确格式化输出的最佳方法是什么?
在研究的过程中,我发现 LLVM 是这样操作的:(found here)
// [string.view.io]
template<class _CharT, class _Traits>
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, basic_string_view<_CharT, _Traits> __sv)
{
return _VSTD::__put_character_sequence(__os, __sv.data(), __sv.size());
}
__put_character_sequence 的实现驻留在in this file,但它大量使用内部函数来进行格式化。我需要自己重新实现所有格式吗?
【问题讨论】:
-
格式化是关于适当的文本对齐的填充(如表格列格式化)——这是很少需要的,所以这一切都归结为你的需要:如果你正在编写一个库,那么有人会来回来困扰你;如果您的程序不关心它,您可以忽略它。此外,填充代码看起来并不复杂也不长——你也可以添加它。
-
@Alexey Guseynov 由于
string_view的长度是运行时值,我不知道如何为此使用自定义特征类型,因为它的构造(我可以用来提供我的运行时长度值)发生在你提到的operator<<重载中,我无法控制。 -
我没有看到任何真正的方法可以避免自己处理格式。可能看起来很奇怪(对我来说有点),但有时这就是生活。幸运的是,字符串的格式非常少。
-
您可以使用
ios_base::width()检索当前宽度。您还需要查看left与right和(如果没有记错的话)fixed以确定在何处插入填充,以及是否截断到字段宽度(使用ios_base::fmtflags()检索) .嗯...哦,如果您要进行填充,您还需要读取当前的填充字符(使用ios_base::fill())。
标签: c++ c++17 string-view