我正在考虑为某些数学类(矩阵,向量等)提供ostream
运算符。朋友已经注意到ostream
std::complex
运算符的gcc标准库实现}包括内部使用字符串流来格式化输出,然后将其传递给实际的ostream
:
/// Insertion operator for complex values.
template<typename _Tp, typename _CharT, class _Traits>
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, const complex<_Tp>& __x)
{
basic_ostringstream<_CharT, _Traits> __s;
__s.flags(__os.flags());
__s.imbue(__os.getloc());
__s.precision(__os.precision());
__s << '(' << __x.real() << ',' << __x.imag() << ')';
return __os << __s.str();
}
这种模式在增强中也是可见的。我们正试图确定这是否值得关注。有人担心它涉及为字符串流包含一个额外的头,并且在字符串流中需要额外的堆分配,这可能是可以避免的。
最合理的是,有人建议如果客户端需要该功能,那么他们可以创建字符串流并自行进行预传。
任何人都可以帮助我理解为什么这会被视为良好做法以及我是否应该采用它?
答案 0 :(得分:6)
考虑如果在ostream上设置输出宽度然后将std :: complex写入其中会发生什么 - 您不希望宽度仅影响第一个输出操作(即'('
字符)
std::complex i(0, 1);
std::cout << std::setw(10) << std::left << i;
这应打印"(0,1) "
而不是"( 0,1)"
通过将整个输出形成为单个字符串,然后将其写出输出,可以识别字段宽度和流上设置的其他格式标记。
答案 1 :(得分:4)
另一个响应中引用的线程原因不会真正解决:字符串仍然可以在流缓冲区级别上拆分,因为从多个线程调用时这些操作不是原子的。
但是,有两个相关的考虑因素:
width()
的含义是整个格式化字符串至少应占用的字符数。如果在内部对另一个输出运算符使用输出运算符,则会使第一个元素占用宽度,而不是由多个组件组成的结果整个字符串。例如,对于复数,真实元素将占用width()
,而不是真元素,逗号和虚元素的组合。答案 2 :(得分:2)
此模式的一个主要目的是避免保留原始流的操纵器/标志并在返回之前重置它们。 Boost.IoStateSavers不需要这样做,所以我想说使用这个库会更好。