2013-02-12 15 views
5

Aktualnie piszę wrapper dla std::stringstream i chcę przesłać wszystkie wywołania operator<< przez moją klasę do std::stringstream. To działa dobrze teraz (dzięki temu pytaniu: wrapper class for STL stream: forward operator<< calls), ale nadal istnieje jeden problem z tym.Klasa opakowująca C++ dla iostream, użyj modyfikatorów strumienia takich jak std :: endl z operatorem <<

Powiedzmy mam następujący kod:

class StreamWrapper { 
private: 
    std::stringstream buffer; 
public: 
    template<typename T> 
    void write(T &t); 

    template<typename T> 
    friend StreamWrapper& operator<<(StreamWrapper& o, T const& t); 

    // other stuff ... 
}; 


template<typename T> 
StreamWrapper& operator<<(StreamWrapper& o, T const& t) { 
    o.write(t); 
    return o; 
} 

template<typename T> 
void StreamWrapper::write(T& t) { 
    // other stuff ... 

    buffer << t; 

    // other stuff ... 
} 

Gdybym teraz to zrobić:

StreamWrapper wrapper; 
wrapper << "text" << 15 << "stuff"; 

Działa to dobrze. Ale jeśli chcę użyć modyfikatorów strumienia, takich jak std::endl, który jest funkcją według http://www.cplusplus.com/reference/ios/endl, po prostu się nie kompiluję.

StreamWrapper wrapper; 
wrapper << "text" << 15 << "stuff" << std::endl; 

Dlaczego? W jaki sposób mogę również przekazać dalej modyfikatory strumienia?

+0

Co znajduje się błąd kompilacji? –

+0

Występują przeciążenia 'operator <<', które pobierają funkcję, a następnie wywołują tę funkcję w strumieniu: http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt http: //en.cppreference .com/w/cpp/io/manip – BoBTFish

Odpowiedz

3

Zobacz this answer.

będziemy chcieli

typedef std::ostream& (*STRFUNC)(std::ostream&); 

StreamWrapper& operator<<(STRFUNC func) // as a member, othewise you need the additional StreamWrappe& argument first 
{ 
    this->write(func); 
    return *this; 
} 
+0

@Mogria dlaczego edycja? Obiekty 'STRFUNC' są funkcjami (wskaźnikami), więc można je wywoływać bezpośrednio na' ostream'. – rubenvb

+0

, ponieważ musi przejść przez moją metodę zapisu, z powodu innych rzeczy w niej zawartych. – MarcDefiant

2

Wydaje się robić trochę dodatkowej pracy. I normalnie używać:

class StreamWrapper 
{ 
    // ... 
public: 
    template <typename T> 
    StreamWrapper& operator<<(T const& obj) 
    { 
     // ... 
    } 
}; 

Dzięki nowoczesnym kompilatora, to powinien praca dla wszystkich betonowych typów. Problem polega na tym, że manipulatory są funkcjami szablonu, więc kompilator nie może wykonać dedukcji typu szablonu: . Rozwiązaniem jest zapewnienie przeciążeń bez szablonów dla typów manipulatorów:

StreamWrapper& operator<<(std::ostream& (*pf)(std::ostream&)) 
{ 
    // For manipulators... 
} 

StreamWrapper& operator<<(std::basic_ios<char>& (*pf)(std::basic_ios<char>&) 
{ 
    // For manipulators... 
} 

Rodzaj odliczenie zawiedzie dla manipulatorów, ale kompilator odbierze te dla rozdzielczości przeciążenia funkcji.

(Należy pamiętać, że konieczne może być nawet więcej, bo takie rzeczy jak std::setw(int).)

+0

Czy idealny idiom przesyłania dalej łagodzi problem, jeśli masz wsparcie odniesienia do wartości r? –

+0

@Tim Nie sądzę. Nie widzę od ręki, jak to by wszystko zmieniło. Według Scotta Meyera (któremu zdecydowanie ufam), nazwy szablonów nie mogą być perfekcyjnie przekazane dalej (i nie widzę sposobu, w jaki można to zaimplementować w kompilatorze), a manipulatory to wszystkie nazwy szablonów. –

+0

Jeśli to powiedział, to też ufam. Miałem w pamięci tylko powtarzające się stwierdzenia, że ​​uniwersalne odniesienia "wiążą się ze wszystkim". –

Powiązane problemy