2011-12-09 14 views
8

Tengo una clase de C++ en la que me gustaría mantener una secuencia utilizada para el registro.Flujo de C++ como variable miembro

La secuencia se debe poder establecer (y posiblemente restablecer) después de la construcción del objeto.

Debe ser posible establecer la secuencia como std::cout, o como un flujo de archivos para iniciar sesión en un archivo, o como un stringstream que no hace más que ignorar los datos (un /dev/null de tipo). En cualquier caso, debe ser un objeto de tipo ostream, que el creador del objeto puede restablecer en cualquier momento. La clase en sí no tiene en cuenta el tipo de flujo concreto.

pude lograr esto con un puntero a un ostream, pero entonces la sintaxis se convierte en un poco molesto, tener que utilizar el operador DEREF:

(*m_log) << "message"; 

en lugar de

m_log << "message"; 

pero puedo No use referencias, ya que el objeto de transmisión debe posiblemente restablecerse después de que el objeto se haya inicializado.

¿Existe una forma elegante de lograr esto, es decir, evitar el uso de punteros, pero aún así ser capaz de restablecer después de la construcción?

+2

¿Por qué no proporcionar una pequeña función miembro devolver una referencia a su torrente? algo en el camino de: ostream & mlog() {return * m_log;}. Luego escribiría: mlog() << "mensaje"; – fjardon

+0

Use un puntero y comience su función con 'std :: ostream & o = * m_log;'. –

+2

@fjardon: ¿Por qué no lo proporciona como una respuesta pequeña? ; P – Xeo

Respuesta

9

Puede restablecer corrientes: ver en vivo en https://ideone.com/Ci4eo

#include <fstream> 
#include <iostream> 
#include <string> 

struct Logger 
{ 
    Logger(std::ostream& os) : m_log(os.rdbuf()) { } 

    std::streambuf* reset(std::ostream& os) 
    { 
     return m_log.rdbuf(os.rdbuf()); 
    } 

    template <typename T> friend Logger& operator<<(Logger& os, const T& t) 
    { os.m_log << t; return os; } 

    friend Logger& operator<<(Logger& os, std::ostream& (*pf)(std::ostream&)) 
    { os.m_log << pf; return os; } 

    private: 
    std::ostream m_log; 
}; 

int main(int argc, const char *argv[]) 
{ 
    Logger logto(std::cout); 

    logto << "Hello world" << std::endl; 

    logto.reset(std::cerr); 
    logto << "Error world" << std::endl; 

    return 0; 
} 
+0

Esta es una buena solución, exactamente en la misma línea de lo que estaba buscando para. Podría expandirse para (opcionalmente) agregar una segunda transmisión, por ejemplo, crear una T. Subiría esto ... si tuviera suficiente reputación. (: Gracias. –

+0

Si está buscando instalaciones como Tee-streams, eche un vistazo a [Boost Iostreams] (http://www.boost.org/doc/libs/1_48_0/libs/iostreams/doc/index. html? path = 1), por ejemplo, [Tee Filter] (http://www.boost.org/doc/libs/1_48_0/libs/iostreams/doc/functions/tee.html#tee_filter) en combinación con [Pipelines] (http://www.boost.org/doc/libs/1_48_0/libs/iostreams/doc/guide/pipelines.html) – sehe

4

¿Por qué molestarse?

class foo{ 
public: 
    // .. 
private: 
    std::ostream& log() const{ return *m_log; } 
    mutable std::ostream* m_log; 
}; 

Y sólo tiene que utilizar log() << "blah\n"; lugar.

+1

Quiere decir 'return * m_log;' en la función, por supuesto. –

+1

@James: No tengo idea de lo que quieres decir. ♪ – Xeo

+0

No había * en el método de registro antes de actualizar la página. –

Cuestiones relacionadas