2013-02-12 14 views
5

Attualmente sto scrivendo un wrapper per un std::stringstream e voglio inoltrare tutte le chiamate operator<< attraverso la mia classe allo std::stringstream. Questo funziona bene ora (grazie a questa domanda: wrapper class for STL stream: forward operator<< calls), ma c'è ancora un problema con esso.Classe wrapper C++ per iostream, utilizzare modificatori di flusso come std :: endl con operatore <<

Diciamo che ho il seguente codice:

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 ... 
} 

Se ora faccio questo:

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

Questo funziona bene. Ma se voglio usare i modificatori di flusso come std::endl, che è una funzione in base a http://www.cplusplus.com/reference/ios/endl, semplicemente non compilo.

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

Perché? Come posso inoltrare anche i modificatori di flusso?

+0

Qual è l'errore di compilazione? –

+0

Esistono sovraccarichi di 'operatore <<' che accetta una funzione, quindi chiama tale funzione nello stream: http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt http: //en.cppreference .com/w/cpp/io/manip – BoBTFish

risposta

3

Vedere this answer.

Vorrete

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 perché la modifica? Gli oggetti 'STRFUNC' sono funzione (puntatori), quindi possono essere chiamati direttamente su 'ostream'. – rubenvb

+0

perché ha bisogno di passare attraverso il mio metodo di scrittura, a causa delle altre cose in esso. – MarcDefiant

2

Sembra che tu stia facendo un po 'di lavoro extra. Io di solito uso:

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

con un compilatore moderno, questo dovrebbe lavoro per tutti i tipi concreti . Il problema è che i manipolatori sono funzioni modello, , quindi il compilatore non è in grado di eseguire la deduzione del tipo di argomento modello . La soluzione è quella di fornire sovraccarichi non template per i tipi di manipolatori:

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

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

Tipo deduzione fallirà per i manipolatori, ma il compilatore prenderà questi per la risoluzione funzione di sovraccarico.

(Si noti che potrebbe essere necessario ancora di più, per cose come std::setw(int).)

+0

L'idioma di inoltro perfetto allevierà il problema se si dispone di supporto per il riferimento del valore r? –

+0

@ Tim non credo. Non vedo come cambierebbe nulla. Secondo Scott Meyer (di cui mi fido sicuramente), i nomi dei template non possono essere inoltrati in modo perfetto (e non vedo come si possa implementarlo in un compilatore), ei manipolatori sono tutti nomi di template. –

+0

Se l'ha detto, allora mi fido anche io. Avevo solo nella memoria le sue ripetute affermazioni che riferimenti universali "legano a tutto". –

Problemi correlati