在实现C++1z的std::basic_string_view以便在旧编译器上使用时,我遇到了一个问题,即它的流输出运算符重载link1。基本上,它必须输出由string_view引用的内容,同时不依赖于任何空终止符(因为string_view不能保证是空终止的)。
通常,编写operator<<的重载非常容易,因为您可以依赖已经存在的重载,因此不需要使用entry对象如SO上的这个问题中所提到的。
但在这种情况下,没有预定义的operator<<重载,它接受字符指针和长度(显然)。因此,在我的当前实现中,我创建了一个临时的std::string实例:
这个方法是可行的,但我非常不喜欢必须创建临时的std::string实例,因为这会导致数据冗余复制和潜在的动态内存使用。在我看来,这至少违背了使用轻量级引用类型的初衷。
所以我的问题是:
什么是在没有开销的情况下实现正确格式化输出我的string_view的最佳方法?
通常,编写operator<<的重载非常容易,因为您可以依赖已经存在的重载,因此不需要使用entry对象如SO上的这个问题中所提到的。
但在这种情况下,没有预定义的operator<<重载,它接受字符指针和长度(显然)。因此,在我的当前实现中,我创建了一个临时的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是这样做的:(在这里找到)
// [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
的实现位于这个文件中, 但它大量使用了内部函数来进行格式化。我需要自己重新实现所有的格式化吗?
ios_base::width()
获取当前宽度。您还需要查看left
vs.right
,以及(如果记忆无误)fixed
,以确定在哪里插入填充,并且是否要截断到字段宽度(使用ios_base::fmtflags()
检索)。嗯...哦,如果您要进行填充,还需要读取当前的填充字符(使用ios_base::fill()
)。 - Jerry Coffin