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

时间:2017-09-30 18:49:04

标签: c++ c++11 operator-overloading iostream

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

char类型的overloadsstring类型和rvalue流定义为免费的namespace - 范围函数,例如:

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

虽然算术类型overloadsstreambuf和流操作符被定义为std::ostream的成员函数,例如:

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

我的问题

这种区别是否有原因?我理解对这些运算符重载的调用操作稍有不同(即空闲namespace - 范围定义的ADL),因此我认为出于优化目的,可能会偏好特定类型的运算符重载。但是这里std::ostream对不同类型使用两种类型的定义。这种语义或实现优化是否有任何优势?

1 个答案:

答案 0 :(得分:5)

  

我认为出于优化目的,可能会偏好特定类型的运算符重载

嗯,不。在一天结束时,两者都作为函数调用执行。重载决策本身甚至没有明显的含义。由于标准规定在[over.match],段落26

  

如果任一操作数的类型是类或枚举,则a   可以声明用户定义的操作符函数来实现它   可能需要运算符或用户定义的转换来转换   操作数适用于内置运算符的类型。在这   case,重载决策用于确定哪个运算符函数   或调用内置运算符来实现运算符。

     

重载解析的候选函数集是。的并集   会员候选人,非会员候选人和内置人员   候选人。参数列表包含的所有操作数   运营商。候选函数集中的最佳函数是   根据[over.match.viable]和[over.match.best]选择。

所有这些操作员重载都是一起解决的。唯一的语义差异是从ostream派生的类可能会选择隐藏某些成员重载。这是根据派生类中的重载方式来完成的。只有明确声明的重载才适用。与那些成员不同,自由函数重载将始终参与重载解析,即使对于派生自ostream的类也是如此。

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

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

正如W.F.所指出的那样。 ostream实际上是basic_ostream<char>。自由函数恰好适用于仅需要流式传输的数据。流本地“字母”中的字符或字符串。因此,对于basic_ostream<wchar_t>,这些免费功能会接受wchar_twchar_t*。简单的流媒体很可能不需要访问流私有部分。

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