【问题标题】:Overload of operator<< with basic_ostream使用 basic_ostream 重载 operator<<
【发布时间】:2015-11-02 12:15:46
【问题描述】:

为什么带有用户定义类C 的流操作的典型标头通常是这样的:

std::ostream& operator<<(std::ostream& os, const C& c);
std::istream& operator>>(std::istream& is, C&);

不是这样的:

template <class CharT, class Traits> 
std::basic_ostream<CharT, Traits>& operator<<(
        std::basic_ostream<CharT, Traits>& os
        const C& c);

template <class CharT, class Traits> 
std::basic_istream<CharT, Traits>& operator>>(
        std::basic_istream<CharT, Traits>& is
        C& c);

我的问题是为什么流运算符的通常重载是用std::ostream 完成的,这是charstd::basic_ostream 的typedef,为什么不直接用std::basic_ostream 完成?

例如:

class C
{
    ...
};

std::ostream& operator<<(std::ostream& os, const C& c)
{
    ...
}

int main()
{
    C c;
    std::wofstream myFile("myFile.txt");
    myFile << c; //Impossible
}

这里写的operator&lt;&lt; 限制我们只能使用专用于char 的流对象(std::ostreamstd::ostringstream,...)。 所以如果使用std::ostreamstd::basic_ostream 更受限制, 为什么在谈论流运算符重载时从未提及std::basic_ostream

【问题讨论】:

  • 很难关注你,请澄清你的问题...你的意思是问为什么使用std::ostreamstd::basic_ostream更常用?
  • 主要是因为提及它会引入与讨论无关的不相关的并发症。您应该能够根据需要从细节中进行概括。
  • 如果你的函数是通用的,那么你必须在一个函数中处理转换为所有不同的字符类型。恕我直言,当您准确指定流类型时,这更容易做到。
  • @NathanOliver 对于内置类型,转换已经完成,如果你想写额外的字符,你可以使用 std::basic_ios::do_widen 。我不认为这真的很烦人,而且这更通用,不是吗?
  • @ThéoVerhelst 走另一条路怎么样?您的班级拥有大量数据,有人想使用 ofstream 吗?

标签: c++ templates operator-overloading std stream-operators


【解决方案1】:

实际上,使用了两种不同的字符类型:

  1. Windows 使用 wchar_t 是因为 Unicode 人很久以前做出的承诺(Unicode 将只使用 16 位,并且每个字符仅由一个单元组成),并且自那以后就被打破了。李>
  2. 其他人都使用char,它现在主要被认为是 UTF-8 编码中的一个字节(显然,不是普遍的)。

回想起来,引入wchar_t(甚至更多的是char16_tchar32_t)是不明智的,如果只使用char,世界会变得更好。因此,那些不受 Windows 困扰的人并不关心 I/O 操作的wchar_t 版本,并且 Windows 通常似乎在 IOStreams 上进行攻击(众所周知,MSVC++ 实现很慢并且意图为零做任何事情)。

另一个原因是,编写模板化 I/O 操作符会增加已经很复杂的系统的复杂性。似乎很少有人了解 IOStreams,而其中对支持多种字符类型感兴趣的人更少。

模板化 I/O 操作符的感知复杂性的一个方面是假设实现需要进入标头,这当然不正确,因为 IOStreams 基本上只有两种字符类型被实例化(@ 987654329@ 和 wchar_t):虽然 IOStreams 可以用其他字符类型实例化,但我很确定几乎没有人真正这样做。尽管我知道这需要什么,但我可能仍需要至少一天的时间来定义所有必要的方面。因此,模板定义可以在合适的翻译单元中定义并在那里实例化。或者,与其将运算符定义为模板,不如将它们完全专门化。

独立于模板化操作符的定义方式,一般来说工作量更大。如果天真地完成(即直接使用例如std::ctype&lt;cT&gt;),结果会很慢,如果做得正确(即缓存来自std::ctype&lt;cT&gt;的结果),它会非常复杂。

综合考虑:何必呢?

如果我必须写入std::wostream 或从std::wistream 读取,我实际上会创建一个过滤流缓冲区,它只使用合适的std::codecvt&lt;...&gt; facet(甚至只使用@987654336)转换写入/读取的字符@ 的 widen()narrow())。它不会处理字符串的正确国际化,但std::locale 设施无论如何都不能真正达到正确的国际化(为此您需要ICU 之类的东西)。

【讨论】:

  • 很好的反应,有道理。还有一个小问题:如果 IOStream 很慢且未使用,如何使用 Windows 进行流式传输和打印到标准输出?
  • 即使在 Windows 上你也可以使用 std::cout 并且它必须写入标准输出。只是大多数 Windows API 使用wchar_t。您也可以使用std::wcout,因为std::basic_ostream&lt;...&gt; 支持由C++ 标准定义的输出运算符。不过,它仍然很慢。除了使用 IOStreams 之外,还有其他 API 也可以写入标准输出。但是,它们不是由 C++ 标准定义的,也不是可移植的。
猜你喜欢
  • 2012-02-08
  • 2013-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多