使用 basic_ostream 重载运算符 <<

Overload of operator<< with basic_ostream

为什么使用 user-defined class C 的典型 header 流操作通常是这样的:

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 完成的,它是 std::basic_ostreamchar 的类型定义,为什么不直接用 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<< 限制我们只能使用专用于 char 的流 object (std::ostream, std::ostringstream, ...) . 因此,如果使用 std::ostreamstd::basic_ostream 更受限制, 为什么在谈论流运算符重载时从未提及 std::basic_ostream

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

  1. Windows 使用 wchar_t 作为 Unicode 人很久以前的承诺(Unicode 只使用 16 位,每个字符只包含一个单位)和从那以后就坏了。
  2. 其他人都使用 char,它现在大多被认为是 UTF-8 编码中的一个字节(显然,不是普遍的)。

回想起来,wchar_t(甚至 char16_tchar32_t)的引入是 ill-advised,如果只有 char 将被使用。结果,那些不被 Windows 打扰的人不关心 I/O 操作的 wchar_t 版本,并且 Windows 通常似乎在 IOStreams 上下注(众所周知,MSVC++ 的实现速度很慢,对此采取任何措施的意愿为零)。

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

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

与模板化运算符的定义方式无关,通常工作量更大。如果天真地完成(即直接使用例如 std::ctype<cT>),结果会很慢,如果做得正确(即缓存来自 std::ctype<cT> 的结果),它将非常复杂。

综上所述:何必呢?

如果我必须写入 std::wostream 或从 std::wistream 读取,我实际上会创建一个过滤流缓冲区,它只使用合适的 [=23] 翻译字符 written/read =] 方面(或者甚至只是使用 std::ctype<wchar_t>widen()narrow())。它不会处理字符串的正确国际化,但是 std::locale 设施无论如何都不能真正达到正确的国际化(你需要像 ICU 这样的东西)。