Порядок исполнения в операторе <<
У меня есть трудности в понимании последовательности вызовов в коде ниже.
Я ожидал увидеть результат ниже
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 );
}
Ответы
Ответ 1
Компилятор может оценить функцию 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). Стандарт не говорит больше, и вы можете ожидать разные результаты с разными компиляторами на С++.
Ответ 2
Порядок выполнения <<
хорошо определен, но порядок вычисления подвыражений не определен в C++. Эта статья и пример кода C иллюстрируют упомянутую проблему.
BA12
и AB12
являются правильными. В следующем коде:
std::cout<< b->fooA() << b->fooB()
1
появится до 2
, но A
может появиться до или после B
, поскольку компилятор не обещает, будет ли он сначала оценивать fooA
или fooB
.
Ответ 3
Операторы сдвига лево-ассоциативны; 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