Бьерн Страуструп - Язык программирования С++. Главы 8-10

ОГЛАВЛЕНИЕ

10.2 ВЫВОД

Строгую типовуюиединообразнуюработу как со встроенными,так и спользовательскими типамиможнообеспечить,если использовать единственное перегруженное имя функции для различных операций вывода.
Например:
     put(cerr,"x = "); // cerr - выходной поток ошибок
     put(cerr,x);
     put(cerr,'\n');
Тип аргумента определяет какую функцию надо вызывать в каждом случае. Такой подход применяется в нескольких языках, однако, это слишком длинная запись. За счет перегрузки операции << , чтобы она означала
"вывести" ("put to"), можно получить более простую запись и разрешить программисту выводить в одном операторе последовательность объектов, например так:
    cerr << "x = " << x << '\n';
Здесь cerr обозначает стандартный поток ошибок. Так, если х типа int со значением 123, то приведенный оператор выдаст
    x = 123
и еще символ конца строки в стандартный поток ошибок. Аналогично, если х имеет пользовательский тип complex со значением (1,2.4), то указанный оператор выдаст
    x = (1,2.4)
в поток cerr. Такой подход легко использовать пока x такого типа, для которого определена операция <<,а пользователь может просто доопределить << для новых типов.

Мы использовали операцию вывода, чтобы избежать многословности, неизбежной, если применять функцию вывода. Но почему именно символ << ? Невозможно изобрести новую лексему (см.  7.2).Кандидатом для ввода и вывода была операция присваивания, но большинство людей предпочитает, чтобы операции ввода и вывода были различны. Более того, порядок выполнения операции = неподходящий, так cout=a=b означает cout=(a=b).  Пробовали использовать операции < и >, но к ним так крепко привязано понятие "меньше чем" и "больше чем", что операции ввода-вывода с ними во всех практически случаях не поддавались прочтению.

Операции << и >> похоже не создают таких проблем. Они асиметричны, что позволяет приписывать им смысл "в" и "из". Они не относятся к числу наиболее часто используемых операций над встроенными типами, а приоритет << достаточно низкий, чтобы писать арифметические выражения в качестве операнда без скобок:

     cout << "a*b+c=" << a*b+c << '\n';
Скобки нужны, если выражение содержит операции с более низким приоритетом:
     cout << "a^b|c=" << (a^b|c) << '\n';
Операцию сдвига влево можно использовать в операции вывода, но, конечно, она должна быть в скобках:
     cout << "a<<b=" << (a<<b) << '\n';