我很难理解下面代码中的调用顺序。我期待看到下面的输出
A1B2
虽然我可以看到我得到的输出是
BA12
我以为呼叫std::cout<< b->fooA() << b->fooB() << std::endl
等同于呼叫
std::cout.operator<<( b->fooA() ).operator<< ( b->fooB() )
但我可以看到情况并非如此。你能帮助我更好地理解它是如何工作的以及与全球operator<<
的关系吗?这是这个序列中最后一个被调用的吗?
#include <iostream>
struct cbase{
int fooA(){
std::cout<<"A";
return 1;
}
int fooB(){
std::cout <<"B";
return 2;
}
};
void printcbase(cbase* b ){
std::cout << b->fooA() << b->fooB() << std::endl;
}
int main(){
cbase b;
printcbase( &b );
}
可以按如下方式计算函数printcbase()
:
void printcbase(cbase* b ){
int a = b->FooA(); // line 1
int b = b->FooB(); // line 2
std::cout << a; // line 3
std::cout << b; // line 4
stc::cout << std::endl;
}
或标记为 1 - 4 的许多行的排列中的一些。您只能保证第 1 行在第 3 行之前完成,第 2 行在第 4 行之前完成(当然第 3 行在第 4 行之前(。标准并没有说更多,事实上,您可以使用不同的C++编译器期待不同的结果。
<<
的执行顺序定义得很好,但子表达式的计算顺序没有在C++中定义。本文和 C 代码示例说明了您提到的问题。
BA12
和AB12
都是正确的。在下面的代码中:
std::cout<< b->fooA() << b->fooB()
1
将出现在2
之前,但A
可能出现在B
之前或之后,因为编译器不承诺它是先计算fooA
还是先计算fooB
。
移位运算符是左关联的; a << b << c
读作(a << b) << c
,这意味着如果a
是具有成员用户定义operator<<
的类型(并返回该类型(,则表达式读作a.operator<<(b).operator<<(c)
。 如果使用免费operator<<
,则读作 operator<<(operator<<(a, b), c)
。
所以a << b
的评估是在(a << b) << c
的评估之前排序的,但是b
和c
的评估之间没有排序依赖关系:
a << b << c[1]
| |
a << b[2] |
| | c[5]
a[3] b[4]
如果我们按上述方式对副作用进行编号,则可以将副作用排序为:
54321
53421
45321
43521
43251
35421
34521
34251
自 C++17 起,从 https://en.cppreference.com/w/cpp/language/eval_order
- 在移位运算符表达式
。E1 << E2
和E1 >> E2
中,E1 的每个值计算和副作用都先于每个值计算和 E2 的副作用进行排序
您保证:
std::cout << b->fooA() << b->fooB() << std::endl;
// (((std::cout << b->fooA()) << b->fooB()) << std::endl);
从左到右求值,导致输出A1B2
。
对于以前的版本,对输出的保证仅为:
-
A
1
之前 -
2
前B
-
1
2
之前
所以A1B2
之一,AB12
,BA12
。