静态与成员运算符重载:标准::运算符<< 和 std::ostream::运算符<<

Static vs. Member Operator Overloads: std::operator<< and std::ostream::operator<<

本文关键字:lt 运算符 ostream std 标准 成员 重载 静态      更新时间:2023-10-16

C 的ostream类为operator<<提供了许多默认过载,但是它们并非全部以相同的方式定义。

char类型,string类型和RVALUE流的过载定义为免费的namespace -Scope功能,例如:

namespace std {
ostream &operator<<(ostream &os, char c);
}

算术类型的过载,streambuf和流操作器被定义为std::ostream的成员函数,例如:

namespace std {
ostream &ostream::operator<<(int val);
}

我的问题

有这种区别的原因吗?我了解对这些操作员过载的调用略有不同(即免费的namespace-Scope定义的ADL),因此我想可能会偏爱特定类型的操作员超载以进行优化。但是在这里,std::ostream使用两种类型的定义用于不同类型。该语义上有任何优势或实现优化的优化吗?

我想可能会偏爱特定类型的操作员过载以进行优化

好吧,不。归根结底,两者都是作为函数调用的。对于超负荷分辨率本身,甚至没有明显的影响。由于该标准在[over.Match]上决定,第2段和6段:

如果任何操作数具有类别是类或枚举的类型, 用户定义的运算符函数可能会声明实现此处 操作员或用户定义的转换可能需要转换 操作数适用于适合内置操作员的类型。在这个 情况,超载分辨率用于确定哪个操作员功能 或内置运算符应调用以实现操作员。

超载分辨率的一组候选功能是 会员候选人,非成员候选人和内置的 候选人。参数列表包含所有操作数 操作员。一组候选功能的最佳功能是 根据[over.match.viable]和[over.match.best]选择。

所有这些操作员的过载都可以解决。唯一的语义差异是从ostream派生的类可以选择 hide 某些成员过载。这是根据超载在派生类中的工作方式来完成的。只有明确声明的过载才适用。与这些成员不同,即使是从ostream派生的类。

由于需要将派生类转换为ostream&,以便选择自由功能过载,因此需要对其自身的隐式转换序列进行排名。如果所有过载都是免费功能,则可能会导致歧义。

因此,考虑因素很可能是将可能导致歧义(指针和算术类型)的类型分开,我们可能总是希望拥有可用的类型(对C串和单个字符的指针)。并允许隐藏"不太有用"的人以避免这些歧义。


正如W.F.指出的那样ostream实际上是basic_ostream<char>。免费功能恰好是仅需要流式传输的数据。流中的字符或字符串本机"字母"。因此,对于basic_ostream<wchar_t>,这些免费功能将接受wchar_twchar_t*。简单的流很可能不需要任何访问流私有部分的访问。

其他过载是用于在流式传输之前序列化的数据。由于所述序列化与流的内部状态紧密相结合,因此使这些过载成为成员更有意义。