2012-10-15 26 views
8

我正在研究为某些数学类(矩阵,向量等)提供ostream运算符。朋友已经注意到ostream运算符的gcc标准库实现std::complex包括内部使用一个字符串流将它传递给实际ostream之前的输出格式:在ostream函数中使用stringstream

/// 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(); 
} 

这种模式升压可见也。我们试图确定这是否值得关注。有人担心它涉及到为字符串流包含一个额外的头文件,并且可能会避免字符串流中需要额外的堆分配。

最合理的建议是,如果客户端需要该功能,那么他们可以创建字符串流并自行进行预传。

任何人都可以帮助我理解为什么这将被认为是良好的做法,我是否应该采用它?

回答

6

考虑,如果你设置的ostream的输出宽度会发生什么,然后写一个std ::复杂 - 你不想宽度只影响第一输出操作(即'('字符)

std::complex i(0, 1); 
std::cout << std::setw(10) << std::left << i; 

这应该打印"(0,1)     ""(         0,1)"

通过形成作为单个字符串整个输出然后写出来的输出荣誉字段宽度和在流上设置其他格式标志。

2

该模式的一个主要目的是避免保留原始流的操纵器/标志并在返回之前重置它们。 Boost.IoStateSavers避免了这个需要,所以我会说使用这个库是一个更好的做法。

4

在另一个响应中引用的线程原因并不会真正解决:字符串仍然可以在流缓冲级别上拆分,因为这些操作在从多个线程调用时不是原子的。

然而,有两个考虑因素是相关的:

  1. 对于要临时更改格式标志设置一定的输出。例如,要确保某个字符串以十六进制表示形式出现,用于其他十进制表示法,并且希望将该流恢复到其原始状态。
  2. 更重要的是,输出的width()的含义是整个格式字符串至少应占用的字符数。如果在内部将输出运算符用于另一个输出运算符,则会使第一个元素占用宽度,而不是由多个组件组成的整个字符串。例如,对于复数,实数元素将占用width(),而不是实数元素,逗号和虚数元素的组合。