繁体   English   中英

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

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

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

char类型, string类型和rvalue流的重载被定义为free namespace -scope函数,例如:

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

虽然算术类型, streambuf和流操作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派生的类可能会选择隐藏某些成员重载。 这是根据派生类中的重载方式来完成的。 只有明确声明的重载才适用。 与那些成员不同,自由函数重载将始终参与重载解析,即使对于从ostream派生的类也是如此。

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

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


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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM