16.2 Operatory << i >>
Czym są operatory '<<' i '>>'?
Pamiętamy z
            
 rozdziału o operatorach ,
że na przykład instrukcja '
a + b' interpretowana jest tak
naprawdę jako wywołanie funkcji dodającej, a wartości wyrażeń
a
 i 
b, po ewentualnej konwersji, są do tej funkcji
przesyłane jako argumenty.
Podobnie jest dla operatorów '<<' i '>>'. Ich użycie
powoduje wywołanie odpowiedniej funkcji dwuargumentowej, przy czym
jako argumenty przesyłana jest do niej referencja do
obiektu-strumienia występującego po lewej stronie i wartość
wyrażenia po prawej stronie operatora. Funkcja ta jest przeciążona;
wybór konkretnej wersji zależy od typu prawego argumentu.
Tak więc dla typów wbudowanych (i wielu bibliotecznych) działanie
operatora jest dobrze określone; dla typów definiowanych przez
programistę można samemu dostarczyć dodatkowe wersje, co
zademonstrujemy w
      rozdziale o przeciążeniach .
Bardzo ważne jest to, że funkcja wywoływana przez użycie operatora
'<<' lub '>>' jest funkcją rezultatową: prócz
wykonania samej operacji we/wy, zwraca jako rezultat referencję
do tego samego obiektu-strumienia, który był jej pierwszym (lewym)
argumentem. Zatem w
       (cout << x) << y;
wartość wyrażenia w nawiasie jest równoważna
cout,
które w ten sposób staje się ponownie lewym argumentem kolejnego
operatora '<<'. Ponieważ wiązanie operatora '<<'
jest lewe, więc użycie nawiasów w powyższym przykładzie nie
jest konieczne; uzyskujemy dzięki temu możliowość „kaskadowego”
wywołania odpowiednich funkcji:
       cout << x << y << z << v << endl;
lub
       cin >> x >> y >> z >> v;
gdzie, jak pamiętamy, kierunek „strzałek” można rozumieć jako
kierunek przepływu informacji.
Aby wyprowadzić, na ekran czy do pliku, napis reprezentujący
na przykład wartość zmiennej typu
double, trzeba przyjąć
jakąś umowę co do sposobu formatowania. Sposób ten, jak się
przekonamy, można zmieniać.
Domyślnie zmienne typów wbudowanych są wyprowadzane zgodnie z
następującymi domniemaniami:
Strumienie wyjściowe:
- wartości całościowe (jak
int,
short, itd.):
          w systemie dziesiątkowym;
- wartości znakowe: jako pojedyncze znaki;
- wartości zmiennopozycyjne (czyli
float,
double
          i 
long double): w systemie dziesiątkowym, z
          precyzją 6 cyfr. Precyzja oznacza liczbę cyfr znaczących,
          a nie liczbę cyfr po kropce dziesiętnej. Na przykład,
          wypisanie w formacie  domyślnym liczby 200.0/3
          daje 66.6667, a nie 66.666667. Końcowe zera po kropce
          dziesiętnej nie są pisane. Tak więc wartość 1.129996
          zostanie najpierw zaokrąglona do sześciu cyfr znaczących,
          dając 1.13000, a następnie wypisana jako 1.13 (ale na
          przykład wydruk 1.129994 da 1.12999).
          Jeśli po kropce wystąpiłyby same zera,
          to opuszczane są i zera, i sama kropka dziesiętna.
          Jeśli liczba cyfr przed kropką wynosi lub przekracza
          sześć, to wypisane zostaną wszystkie, a część
          ułamkowa zostanie pominięta;
- wartości wskaźnikowe (prócz typu
char*):
          jako dodatnie liczby całkowite reprezentujące adresy w
          pamięci. Adresy wypisywane są w układzie szesnastkowym,
          a więc z prefiksem '0x';
- wartości wskaźnikowe typu
char*: jako napisy,
          interpretując kolejne bajty w pamięci, poczynając od bajtu
          wskazywanego przez wskaźnik, jako zapis kolejnych znaków
          napisu; wypisywanie kończy się po napotkaniu bajtu zerowego
          (odpowiadającego znakowi końca napisu '
\0');
- wartości logiczne (typu
bool): jako liczby 1 i 0.
Strumienie wejściowe:
- wiodące białe znaki są pomijane;
- każda następna niepusta sekwencja białych znaków
          jest interpretowana jako koniec danych. Znaki te pozostają
          w buforze i będą pominięte, jako wiodące, przy następnym
          czytaniu;
- liczby całkowite wczytywane są w postaci
          dziesiętnej; pierwszym niebiałym znakiem może
          być znak '+' lub '-', następnie wczytywane są cyfry
          aż do napotkania znaku nie
          będącego cyfrą — ten znak jest pozostawiany w buforze
          i będzie pierwszym znakiem wczytanym przez następną
          operację czytania. Na przykład, jeśli program czyta
          za pomocą instrukcji 'cin >> x >> y',
          to można podać jako dane 128-25; wczytywanie 128 na
x
 zakończy się na znaku minus, który pozostanie
          w strumieniu. Następnie będzie kontynuowane czytanie
          na
y
 znaków -25;
- liczby zmiennopozycyjne wczytywane są w
          formacie liczb całkowitych bez kropki dziesiętnej,
          w formacie z kropką dziesiętną i w notacji
          „naukowej” (na przykład 1e-1 to to samo co 0.1,
          1.201e+2 to 120.1);
- wartości logiczne mają postać literałów 1 i 0.
T.R. Werner, 21 lutego 2016; 20:17