2014-11-06 23 views
10

Załóżmy, że mam funkcję, która pobiera ostream & parametr o i zapisuje do tego ostream. Implementacja operator << byłaby dobrym przykładem.Czy powinienem utworzyć tymczasowy ostream, używając innego strumienia?

ostream& operator << (ostream& o, const MyThing& t) 
{ 
    // ... interesting code here ... 
    return o; 
} 

W ramach tej funkcji mogę chcieć określić opcje formatowania w strumieniu. Na przykład, mogę chcieć, aby liczba była drukowana w postaci heksadecymalnej, bez względu na konfigurację o, gdy jest przekazywana do funkcji.

Po drugie, mógłbym chcieć mieć założenia dotyczące aktualnych flag formatowania. Na przykład dobrze byłoby móc założyć, że liczby zostały sformatowane jako dziesiętne, o ile nie zażądam inaczej.

Wreszcie, do czasu wyjścia z funkcji chcę, aby opcje formatowania na o były takie same, jak przed wywołaniem funkcji, aby wyglądały niezmiennie dla osoby dzwoniącej. Jest to po prostu kwestia uprzejmości dla osoby dzwoniącej.

Do tej pory udało mi się osiągnąć to poprzez stworzenie lokalnej ostringstream wewnątrz funkcji, czyniąc całą moją pracę na ten temat (w tym ustawiania opcji formatowania), a wysłaniem .str() do o po zakończeniu funkcji. Pytanie StackOverflow here sugeruje, że ludzie sprytniejsi ode mnie stosują to samo podejście. Jednak przeszkadza mi to, że przechowuję tak dużo danych w ostrych strumieniach, które być może zostały wcześniej wysłane do wyjścia (łańcuchy mogą stać się całkiem duże).

Mam dwa pytania:

1) jest to legalne, idiomatyczne, dobrą formę, itp aby utworzyć tymczasowy (stack based) ostream wokół o.rdbuf() i wykonywać moją pracę na tym ostream? Moje własne testy i strona pod adresem cppreference.com sugerują, że mogę.

ostream& operator << (ostream& o_, const MyThing& t) 
{ 
    ostream o (o_.rdbuf()); 
    // write stuff to "o", 
    // setting formatting options as I go. 
    return o_; // Formatting on the parameter ostream o_ unchanged. 
} 

2) Czy istnieje inny, lepszy sposób, którego nie rozważałem?

Odpowiedz

0

Ustawienia mogą być przechowywane w typie obiektu o nazwie obiekt fmtflags, zdefiniowany w klasie o nazwie ios, dołączonej do iostream. Możesz zadeklarować jeden z tych obiektów, ale musisz to zadeklarować za pomocą operatora rozdzielczości zakresu.

następujące oświadczenie zbawi niektórych aspektów stanu formatu w zmiennej old_settings:

ios::fmtflags old_settings = cout.flags(); 

Następnie, po wykonaniu wyjście przy użyciu nowych ustawień, można przywrócić stare ustawienia poprzez wywołanie tej samej funkcji z stare ustawienia jako argument:

cout.flags(old_settings); 

Inne ustawienia można uzyskać i przywrócić za pomocą funkcji składowych. Na przykład:

int old_precision = cout.precision(); 

zapisze bieżącą specyfikację precyzji.Następnie

cout.precision(old_precision); 

przywróci precyzję do pierwotnej wartości

+0

Połączenia te najlepiej znajdować się w konstruktora i destruktora jakiś obiekt oparty na stosie. Zakładam, że to właśnie robią klasy Boost. – peterpi

1

To nie jest złe rozwiązanie; to z pewnością legalne. Nie wydaje mi się, że jest to zbyt częste, więc warto to skomentować jako , dlaczego to robisz.

Najczęstszym rozwiązaniem Widziałem tutaj jest stworzenie stanu klasę wygaszacza, który uratuje wszystkie państwa trzeba (zazwyczaj flags(), precision() i fill()) w konstruktorze i przywrócić go w destruktor, a następnie do ustawicznie ustawić wszystkie żądane opcje. (Może to być możliwe używać copyfmt na to, chociaż to także kopiuje rzeczy jak Maska wyjątek, który prawdopodobnie nie chcą grać.)