使用 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_ostream
的 char
的类型定义,为什么不直接用 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::ostream
比 std::basic_ostream
更受限制,
为什么在谈论流运算符重载时从未提及 std::basic_ostream
?
实际上,使用了两种不同的字符类型:
- Windows 使用
wchar_t
作为 Unicode 人很久以前的承诺(Unicode 只使用 16 位,每个字符只包含一个单位)和从那以后就坏了。
- 其他人都使用
char
,它现在大多被认为是 UTF-8 编码中的一个字节(显然,不是普遍的)。
回想起来,wchar_t
(甚至 char16_t
和 char32_t
)的引入是 ill-advised,如果只有 char
将被使用。结果,那些不被 Windows 打扰的人不关心 I/O 操作的 wchar_t
版本,并且 Windows 通常似乎在 IOStreams 上下注(众所周知,MSVC++ 的实现速度很慢,对此采取任何措施的意愿为零)。
另一个原因是,编写模板化的 I/O 运算符被认为会增加已经很复杂的系统的复杂性。似乎很少有人了解 IOStreams,而在这少数人中,对支持多种字符类型感兴趣的就更少了。
模板化 I/O 运算符的复杂性的一个方面是假设实现需要进入 header 这当然是不正确的,因为基本上只有两个字符类型 IOStreams 是用 (char
和 wchar_t
) 实例化的:尽管 IOStreams 可以 用其他字符类型实例化,但我很确定几乎没有人真正这样做所以。虽然我知道这需要什么,但我可能仍需要至少一天的时间来定义所有必要的方面。因此,模板定义 可以 在合适的翻译单元中定义并在那里实例化。或者,不是定义运算符而是模板,它们可以完全专门化。
与模板化运算符的定义方式无关,通常工作量更大。如果天真地完成(即直接使用例如 std::ctype<cT>
),结果会很慢,如果做得正确(即缓存来自 std::ctype<cT>
的结果),它将非常复杂。
综上所述:何必呢?
如果我必须写入 std::wostream
或从 std::wistream
读取,我实际上会创建一个过滤流缓冲区,它只使用合适的 [=23] 翻译字符 written/read =] 方面(或者甚至只是使用 std::ctype<wchar_t>
的 widen()
或 narrow()
)。它不会处理字符串的正确国际化,但是 std::locale
设施无论如何都不能真正达到正确的国际化(你需要像 ICU 这样的东西)。
为什么使用 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_ostream
的 char
的类型定义,为什么不直接用 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::ostream
比 std::basic_ostream
更受限制,
为什么在谈论流运算符重载时从未提及 std::basic_ostream
?
实际上,使用了两种不同的字符类型:
- Windows 使用
wchar_t
作为 Unicode 人很久以前的承诺(Unicode 只使用 16 位,每个字符只包含一个单位)和从那以后就坏了。 - 其他人都使用
char
,它现在大多被认为是 UTF-8 编码中的一个字节(显然,不是普遍的)。
回想起来,wchar_t
(甚至 char16_t
和 char32_t
)的引入是 ill-advised,如果只有 char
将被使用。结果,那些不被 Windows 打扰的人不关心 I/O 操作的 wchar_t
版本,并且 Windows 通常似乎在 IOStreams 上下注(众所周知,MSVC++ 的实现速度很慢,对此采取任何措施的意愿为零)。
另一个原因是,编写模板化的 I/O 运算符被认为会增加已经很复杂的系统的复杂性。似乎很少有人了解 IOStreams,而在这少数人中,对支持多种字符类型感兴趣的就更少了。
模板化 I/O 运算符的复杂性的一个方面是假设实现需要进入 header 这当然是不正确的,因为基本上只有两个字符类型 IOStreams 是用 (char
和 wchar_t
) 实例化的:尽管 IOStreams 可以 用其他字符类型实例化,但我很确定几乎没有人真正这样做所以。虽然我知道这需要什么,但我可能仍需要至少一天的时间来定义所有必要的方面。因此,模板定义 可以 在合适的翻译单元中定义并在那里实例化。或者,不是定义运算符而是模板,它们可以完全专门化。
与模板化运算符的定义方式无关,通常工作量更大。如果天真地完成(即直接使用例如 std::ctype<cT>
),结果会很慢,如果做得正确(即缓存来自 std::ctype<cT>
的结果),它将非常复杂。
综上所述:何必呢?
如果我必须写入 std::wostream
或从 std::wistream
读取,我实际上会创建一个过滤流缓冲区,它只使用合适的 [=23] 翻译字符 written/read =] 方面(或者甚至只是使用 std::ctype<wchar_t>
的 widen()
或 narrow()
)。它不会处理字符串的正确国际化,但是 std::locale
设施无论如何都不能真正达到正确的国际化(你需要像 ICU 这样的东西)。