Когда оператор & lt; & lt; обратитесь к оператору вставки и когда к битовому сдвигу влево?

Когда делает 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;
}

23

Решение

Проблема, с которой вы столкнулись, не связана с << оператор. В каждом случае оператор вставки вызывается.

Однако вы столкнулись с проблемой, касающейся порядок оценки в командной строке

cout << a.b() << a.a.b << endl;

Функция a.b() имеет побочный эффект. Он меняет значения a.a.a и a.a.b. Таким образом, очевидно, что a.b () вызывается до или после оценки значения ov a.a.b,

В C ++ порядок оценки не указан, см. cppreference.com для более подробного обсуждения.

14

Другие решения

Это выведет 10, и оператор<< обратитесь к левому сдвигу.

соиЬ << a.b () << a.a.b << епсИ;

Это связано с тем, что порядок вычисления операндов не определен. С 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.bG ++ делает это наоборот. Так как ваш a.b() изменяя переменные, вы получаете разные результаты.

Когда вы переписываете свой код как:

cout << a.b();
cout << a.a.b ;

тогда у вас есть два оператора полного выражения, здесь нет неопределенного поведения, связанного с вычислением операнда. Таким образом, вы всегда получаете один и тот же результат.

40

В твоем случае все operator <<s являются операторами вставки выходного потока, потому что их левый аргумент имеет тип ostream&и они группируются слева направо.

Разница в выводе обусловлена ​​порядком вычисления аргументов функции:

cout << a.b() << a.a.b

является

operator<<(operator<<(cout, a.b()), a.a.b)

поэтому выход зависит от того, какой из a.a.b или же a.b() оценивается первым. Это на самом деле не определено текущим стандартом (C ++ 14), чтобы вы могли получить 11 также.

AFAIK в C ++ 17 11 будет единственным допустимым выходным сигналом для обоих случаев, потому что он обеспечивает оценку параметров функции слева направо.

Обновление: это, кажется, не соответствует действительности, как решил комитет (по состоянию на N4606) идти с неопределенно последовательной оценкой параметров, упомянутой внизу P0145R2. См. [Expr.call] / 5.

Обновление 2: поскольку здесь мы говорим о перегруженных операторах, применяется [over.match.oper] / 2 в N4606, в котором говорится

Однако операнды упорядочены в порядке, установленном для встроенного оператора.

Таким образом, порядок оценки будет хорошо определен в C ++ 17. Это недоразумение, по-видимому, было предсказано авторами P0145:

Мы не считаем, что такой недетерминизм приносит какую-либо существенную дополнительную выгоду оптимизации, но он увековечивает путаницу и риски, связанные с порядком оценок в вызовах функций

16

Этот звонок:

cout << a.b() << a.a.b << endl;

сначала рассмотрим:

cout << a.b()

которые соответствуют оператору вставки и возвращают ссылку на cout. Таким образом, инструкция станет:

(returned reference to cout) << a.a.b

который снова вызовет оператор вставки и так далее …

Если ваша инструкция была:

cout << (a.b() << a.a.b) << endl;

часть между скобками будет считаться первой:

a.b() << a.a.b

на этот раз у вас есть оператор между 2 intКомпилятор может разрешить его только как вызов побитового оператора.

9

Бинарные операторы, такие как <<, имеют два свойства, которые определяют их использование: (оператор) приоритет и (слева или справа) ассоциативность. В этом случае ассоциативность является ключом, и, см., Например, http://en.cppreference.com/w/c/language/operator_precedence, << Оператор имеет ассоциативность слева направо, поэтому они упорядочены (как в скобках) слева направо:

((cout << a.b()) << a.a.b) << endl;

или в словах, упорядоченных как cout << a.b() затем << a.a.b а потом << endl,

После этой последовательности перегрузка оператора вступает в силу при каждом вызове << с заданными типами, который затем определяет, какая перегрузка вызывается и, таким образом, если это cout-операция или смена.

9

Без скобок операнды по обе стороны от << определить значение: int << int == shift, stream << any == insertion,
Это «повторное использование» оператора может быть запутанным, нежить. Но вы можете решить неясности, используя скобки: stream << (int << int) == "int"

4
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector