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

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

C++ 的 ostream class 为 operator<< 提供了许多默认重载,但它们的定义方式并不完全相同。

char 类型、string 类型和右值流的 overloads 定义为自由 namespace 作用域函数,例如:

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

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

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

我的问题

这种区别有什么原因吗?我知道对这些运算符重载的调用略有不同(即 ADL 用于自由 namespace-范围定义),因此我想可能出于优化目的而偏好特定类型的运算符重载。但是这里 std::ostream 对不同的类型使用了两种类型的定义。这种允许的语义或实现优化有什么优势吗?

I'd imagine there might be a preference to a particular type of operator overload for optimization purposes

嗯,不。归根结底,两者都被执行为函数调用。重载决议本身甚至没有明显的暗示。由于标准规定在 [over.match],段落 2 and 6:

If either operand has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator or a user-defined conversion can be necessary to convert the operand to a type that is appropriate for a built-in operator. In this case, overload resolution is used to determine which operator function or built-in operator is to be invoked to implement the operator.

The set of candidate functions for overload resolution is the union of the member candidates, the non-member candidates, and the built-in candidates. The argument list contains all of the operands of the operator. The best function from the set of candidate functions is selected according to [over.match.viable] and [over.match.best].

所有这些运算符重载都一起解决了。唯一的语义差异是从 ostream 派生的 class 可以选择 隐藏 某些成员重载。这是根据重载在派生 class 中的工作方式完成的。只有明确声明的重载才适用。与那些成员不同,自由函数重载将始终参与重载决策,即使对于从 ostream.

派生的 classes 也是如此

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

因此,考虑的很可能是将可能导致歧义的类型(指针和算术类型)与我们可能始终希望可用的有用类型(指向 C 字符串和单个字符的指针)分开。并允许隐藏 "less useful" 以避免那些歧义。


正如 W.F 指出的那样。 ostream 实际上是 basic_ostream<char>。免费功能恰好适用于仅需要流式传输的数据。本机流中的字符或字符串 "alphabet"。所以对于 basic_ostream<wchar_t> 那些自由函数将接受 wchar_twchar_t*。简单的流式传输很可能不需要访问流专用部分。

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