operator<< 什么时候指的是插入运算符,什么时候指的是按位左移?
When does operator<< refer to the insertion operator and when to the bitwise left shift?
什么时候operator <<
指的是插入运算符,什么时候指的是按位左移?
这样会输出10
,而operator <<
指的是左移。
cout << a.b() << a.a.b << endl;
这样会输出11
,operator <<
指的是插入运算符。
cout << a.b();
cout << a.a.b ;
我很困惑,什么时候 operator <<
(与 cout
一起使用时)指的是左移运算符?
#include <iostream>
using namespace std;
class A {
public:
A() { a.a = a.b = 1; }
struct { int a, b; } a;
int b();
};
int A::b(){
int x=a.a;
a.a=a.b;
a.b=x;
return x;
};
int main(){
A a;
a.a.a = 0;
a.b();
cout << a.b() << a.a.b << endl; // ?????
return 0;
}
没有括号,<<
两边的操作数决定意义:int << int == shift
、stream << any == insertion
。
这个'reuse'的运算符可能会让人迷惑,死机。但是您可以使用括号解决歧义:stream << (int << int) == "int"
这次通话:
cout << a.b() << a.a.b << endl;
首先会考虑:
cout << a.b()
对应于插入运算符,returns 是对 cout 的引用。因此,指令将变为:
(returned reference to cout) << a.a.b
这将再次调用插入运算符等等...
如果您的指示是:
cout << (a.b() << a.a.b) << endl;
首先考虑括号之间的部分:
a.b() << a.a.b
这一次,你有一个介于 2 int
之间的运算符:编译器只能将其解析为对按位运算符的调用。
二元运算符,例如 <<
,有两个定义其用法的属性:(运算符)优先级和(左或右)结合性。在这种情况下,关联性是关键,并且参见例如http://en.cppreference.com/w/c/language/operator_precedence,<<
运算符具有从左到右的结合性,因此它们从左到右排序(就像用括号一样):
((cout << a.b()) << a.a.b) << endl;
或按 cout << a.b()
然后 << a.a.b
然后 << endl
.
排序的单词
在此排序之后,运算符重载会在每次使用给定类型调用 <<
时生效,然后确定调用哪个重载,从而确定它是 cout
操作还是移位。
This will output 10, and operator<< refer to left shift.
cout << a.b() << a.a.b << endl;
这是由于未指定操作数的计算顺序造成的。使用 clang 它输出 11 但使用 gcc 它输出 10.
您的代码:
cout << a.b() << a.a.b << endl;
可以替换为:
std::cout.operator<<(a.b()).operator<<(a.a.b);
clang 首先计算 a.b()
然后 a.a.b
,g++ 则相反。由于您的 a.b()
修改了变量,因此您会得到不同的结果。
当您将代码重写为:
cout << a.b();
cout << a.a.b ;
那么你有两个完整的表达式语句,这里没有与操作数评估相关的未指定行为。所以你总是得到相同的结果。
在您的例子中,所有 operator <<
都是输出流插入运算符,因为它们的左参数是 ostream&
类型,并且它们从左到右分组。
输出的不同是由函数参数的求值顺序造成的:
cout << a.b() << a.a.b
是
operator<<(operator<<(cout, a.b()), a.a.b)
所以输出取决于 a.a.b
或 a.b()
中的哪一个先被评估。当前标准 (C++14) 实际上并未指定,因此您也可以获得 11
。
C++17 中的 AFAIK 11
将是这两种情况的唯一有效输出,因为它强制对函数参数进行从左到右的评估。
更新:这似乎不是真的,因为委员会决定(截至 N4606) to go with indeterminately sequenced parameter evaluation mentioned at the bottom of P0145R2。见 [expr.call]/5.
更新 2:由于我们在这里讨论的是重载运算符,因此适用 N4606 中的 [over.match.oper]/2,即
However, the operands are sequenced in the order prescribed for the built-in operator.
所以确实,计算的顺序将在 C++17 中得到明确定义。这种误解显然已经被P0145的作者预测到了:
We do not believe that such a nondeterminism brings any substantial added optimization benefit, but it does perpetuate the confusion and hazards around order of evaluations in function calls
您遇到的问题与 << 运算符无关。在每种情况下,都会调用插入运算符。
但是,您在命令行
中遇到了有关 求值顺序 的问题
cout << a.b() << a.a.b << endl;
函数a.b()
有副作用。它交换值 a.a.a 和 a.a.b。因此,很明显,a.b() 是在评估值 ov a.a.b
.
之前还是之后被调用的
在 C++ 中,未指定求值顺序,请参阅 cppreference.com 了解更详细的讨论。
什么时候operator <<
指的是插入运算符,什么时候指的是按位左移?
这样会输出10
,而operator <<
指的是左移。
cout << a.b() << a.a.b << endl;
这样会输出11
,operator <<
指的是插入运算符。
cout << a.b();
cout << a.a.b ;
我很困惑,什么时候 operator <<
(与 cout
一起使用时)指的是左移运算符?
#include <iostream>
using namespace std;
class A {
public:
A() { a.a = a.b = 1; }
struct { int a, b; } a;
int b();
};
int A::b(){
int x=a.a;
a.a=a.b;
a.b=x;
return x;
};
int main(){
A a;
a.a.a = 0;
a.b();
cout << a.b() << a.a.b << endl; // ?????
return 0;
}
没有括号,<<
两边的操作数决定意义:int << int == shift
、stream << any == insertion
。
这个'reuse'的运算符可能会让人迷惑,死机。但是您可以使用括号解决歧义:stream << (int << int) == "int"
这次通话:
cout << a.b() << a.a.b << endl;
首先会考虑:
cout << a.b()
对应于插入运算符,returns 是对 cout 的引用。因此,指令将变为:
(returned reference to cout) << a.a.b
这将再次调用插入运算符等等...
如果您的指示是:
cout << (a.b() << a.a.b) << endl;
首先考虑括号之间的部分:
a.b() << a.a.b
这一次,你有一个介于 2 int
之间的运算符:编译器只能将其解析为对按位运算符的调用。
二元运算符,例如 <<
,有两个定义其用法的属性:(运算符)优先级和(左或右)结合性。在这种情况下,关联性是关键,并且参见例如http://en.cppreference.com/w/c/language/operator_precedence,<<
运算符具有从左到右的结合性,因此它们从左到右排序(就像用括号一样):
((cout << a.b()) << a.a.b) << endl;
或按 cout << a.b()
然后 << a.a.b
然后 << endl
.
在此排序之后,运算符重载会在每次使用给定类型调用 <<
时生效,然后确定调用哪个重载,从而确定它是 cout
操作还是移位。
This will output 10, and operator<< refer to left shift.
cout << a.b() << a.a.b << endl;
这是由于未指定操作数的计算顺序造成的。使用 clang 它输出 11 但使用 gcc 它输出 10.
您的代码:
cout << a.b() << a.a.b << endl;
可以替换为:
std::cout.operator<<(a.b()).operator<<(a.a.b);
clang 首先计算 a.b()
然后 a.a.b
,g++ 则相反。由于您的 a.b()
修改了变量,因此您会得到不同的结果。
当您将代码重写为:
cout << a.b();
cout << a.a.b ;
那么你有两个完整的表达式语句,这里没有与操作数评估相关的未指定行为。所以你总是得到相同的结果。
在您的例子中,所有 operator <<
都是输出流插入运算符,因为它们的左参数是 ostream&
类型,并且它们从左到右分组。
输出的不同是由函数参数的求值顺序造成的:
cout << a.b() << a.a.b
是
operator<<(operator<<(cout, a.b()), a.a.b)
所以输出取决于 a.a.b
或 a.b()
中的哪一个先被评估。当前标准 (C++14) 实际上并未指定,因此您也可以获得 11
。
C++17 中的 AFAIK 11
将是这两种情况的唯一有效输出,因为它强制对函数参数进行从左到右的评估。
更新:这似乎不是真的,因为委员会决定(截至 N4606) to go with indeterminately sequenced parameter evaluation mentioned at the bottom of P0145R2。见 [expr.call]/5.
更新 2:由于我们在这里讨论的是重载运算符,因此适用 N4606 中的 [over.match.oper]/2,即
However, the operands are sequenced in the order prescribed for the built-in operator.
所以确实,计算的顺序将在 C++17 中得到明确定义。这种误解显然已经被P0145的作者预测到了:
We do not believe that such a nondeterminism brings any substantial added optimization benefit, but it does perpetuate the confusion and hazards around order of evaluations in function calls
您遇到的问题与 << 运算符无关。在每种情况下,都会调用插入运算符。
但是,您在命令行
中遇到了有关 求值顺序 的问题cout << a.b() << a.a.b << endl;
函数a.b()
有副作用。它交换值 a.a.a 和 a.a.b。因此,很明显,a.b() 是在评估值 ov a.a.b
.
在 C++ 中,未指定求值顺序,请参阅 cppreference.com 了解更详细的讨论。