2012-10-15 16 views
8

Czekam na dostarczanie operatorów ostream dla niektórych klas matematycznych (macierzy, wektorów itp.) Znajomy zauważył, że implementacja biblioteki standardowej gcc operatora ostream dla std::complex obejmuje wewnętrzne użycie strumień ciąg sformatować wyjście przed przekazaniem go do rzeczywistego ostream:Używanie strumienia w funkcji ostream

/// Insertion operator for complex values. 
template<typename _Tp, typename _CharT, class _Traits> 
    basic_ostream<_CharT, _Traits>& 
    operator<<(basic_ostream<_CharT, _Traits>& __os, const complex<_Tp>& __x) 
{ 
    basic_ostringstream<_CharT, _Traits> __s; 
    __s.flags(__os.flags()); 
    __s.imbue(__os.getloc()); 
    __s.precision(__os.precision()); 
    __s << '(' << __x.real() << ',' << __x.imag() << ')'; 
    return __os << __s.str(); 
} 

Ten wzór jest widoczny w impuls, jak również. Próbujemy ustalić, czy jest to wzór, który warto śledzić. Pojawiły się obawy, że obejmuje to dodanie dodatkowego nagłówka dla strumienia napisów i istnieją dodatkowe przydziały sterty wymagane w strumieniu ciągów, których można potencjalnie uniknąć.

Najprawdopodobniej zasugerowano, że jeśli klient wymaga tej funkcjonalności, może utworzyć strumień ciągów i samemu dokonać wstępnego przejścia.

Czy ktoś może mi pomóc zrozumieć, dlaczego uznano by to za dobrą praktykę i czy powinienem ją przyjąć?

Odpowiedz

6

Zastanów się, co się dzieje, jeśli ustawić szerokość wyjścia na ostream, a następnie napisać std :: złożone do niego - nie chcesz, aby szerokość tylko wpływać na działanie pierwszego wyjścia (czyli charakter '(')

std::complex i(0, 1); 
std::cout << std::setw(10) << std::left << i; 

ten powinien wydrukować "(0,1)     " nie "(         0,1)"

tworząc całą wyjście jako jeden ciąg znaków wtedy pisanie go honory wyjściowe szerokość pola i inne flagi formatowania zawarte w strumieniu.

2

Głównym celem tego wzoru jest unikanie zachowywania manipulatorów/flag oryginalnego strumienia i resetowanie ich przed powrotem. Boost.IoStateSavers eliminuje to zapotrzebowanie, więc chciałbym powiedzieć, że używanie tej biblioteki byłoby lepszą praktyką.

4

Przyczyna wątku cytowana w innej odpowiedzi nie zadziała tak naprawdę: ciąg może zostać podzielony na poziomie bufora strumienia, ponieważ operacje te nie są atomowe, gdy są wywoływane z wielu wątków.

Jednakże istnieją dwa czynniki, które są istotne:

  1. Dla niektórych wyjść Aby tymczasowo zmienić ustawienia formatu flag. Na przykład, chcesz się upewnić, że pewne ciągi pojawiają się przy użyciu notacji szesnastkowej, dla innych notacji dec i chcesz przywrócić strumień do jego pierwotnego stanu.
  2. Co ważniejsze, znaczenie wyjścia width() jest liczbą znaków, które powinien zajmować cały ciąg formatowania. Jeśli wewnętrznie używasz operatorów wyjściowych do innego operatora wyjścia, pierwszy element będzie zajmował szerokość, a nie cały łańcuch składający się z wielu komponentów. Na przykład dla liczby zespolonej rzeczywisty element będzie zajmował width(), a nie kombinację realnego elementu, przecinka i elementu wyobrażonego.
Powiązane problemy