"cout << x"和"cout.operator<<(x)"和"operator(std::cout, x)"之间的区别?

Difference between `cout << x` and `cout.operator<<(x)` and `operator(std::cout, x)`?

本文关键字:lt cout operator 区别 std 之间      更新时间:2023-10-16

这与差异-tween-cout-x和cout-operator-x问题有关,但仍然有点不同。。。

#include <iostream>
int main(){
std::cout << "hello" << std::endl;
std::cout.operator<<("hello2");
std::cout.operator<<(std::endl);
operator<<(std::cout, "hello3");
//    operator<<(std::cout, std::endl);
return 0;
}

Q1:为什么std::cout.operator<<("hello2");有效

从SO的其他答案来看,我希望编译器会抱怨,因为operator<<是一个自由函数,而不是cout的成员。然而,在我的系统上,它会打印"0x10d54df31"。而且,更奇怪的是,下面的行正确地执行了std::endl

Q2:为什么operator<<(std::cout, std::endl);不起作用

我知道std::endl是一个函数,但(对我来说)hello3输出有效,而"std::endl"却无效,这似乎很奇怪。相反,编译器抛出一个错误:

main.cpp:10:4: error: no matching function for call to 'operator<<'
operator<<(std::cout, std::endl);

Q3:第一个std::cout << "hello1" << std::endl;怎么能用operator<<(...)的形式写

如果前两个问题已经得到回答,那么这可能已经涵盖了。这就是这个学习练习的重点,所以明确地问它似乎是明智的。

运算符可以用不同的方式实现,特别是左手边是您类型的operator<<,它可以实现为自由函数或该左手边类型的成员函数。

虽然您必须将ostream& operator<<(ostream&, MyType const&)实现为一个自由函数(因为MyType不是左手边),但库实现可以选择*std::ostream类型中的一些基本类型实现operator<<(这实际上是一个模板的特定实例化,我试图忽略细节)。

编辑:在与标准进行检查后,这是不正确的:

这就是您在代码中注意到的,使用const char*的重载被实现为ostream(basic_ostream<char,char_traits<char>)的成员

重载操作器被实现为成员函数(Q2),如果使用显式调用成员运算符(Q1)的语法,则会选择从const char*const void*的隐式转换。对于第三季度,答案是:

operator<<(std::cout, "Hello").operator<<(std::endl);

*实现实际上并不是可以自由选择的,因为标准要求签名。

operator<<的一些重载是类成员,其他则不是。

在C++03中,这造成了一些令人困惑的调用场景,因为对非const(非成员的参数)的引用不能绑定到右值,但在C++11中,通过引入右值引用参数重载,至少解决了一个这样的问题。

因此,调用compile与否在很大程度上也取决于C++标准版本,即C++03或C++11。

std::ostream中定义了一组成员输出运算符。回想起来,这可能是一个错误,但当IOStreams第一次创建时,我认为这实际上是必要的。这些成员运算符包括采用函数指针的重载,这意味着您需要对这些重载使用成员表示法。使用C字符串的运算符是非成员重载,即,您需要使用非成员函数调用表示法来获得C字符串重载。当您用char const*调用成员运算符时,char const*将转换为有成员输出运算符的void const*

您的问题可以分解为成员函数和非成员函数。

具有13.5.2二进制运算符

应实现二进制运算符通过具有一个参数的非静态成员函数(9.3)或通过具有两个参数的非成员函数。因此,对于任何二进制operator@,x@y可以解释为x.operator@(y)或运算符@(x,y)。如果运算符函数的两种形式都已则13.3.1.2中的规则确定,使用解释。

最好省略13.3.1.2的引用,即成员函数(运算符)。

行"std::cout<lt;"你好"<lt;std::endl;'涉及非成员职能。每个"std::cout.operator"都是一个显式成员函数调用。

  • Q1是成员运算符<lt;(const void*)
  • Q2没有成员执行功能
  • Q3不可能