2011-12-14 65 views
6

me gustaría poner en práctica la clase MyCout, que puede proporcionar posibilidad de endl automática, es decir, el códigomycout endl automática

MyCout mycout; 
mycout<<1<<2<<3; 

salidas

123 
//empty line here 

¿Es posible aplicar clase con tal funcionalidad?


ACTUALIZACIÓN: Soulutions no debería ser así MyCout()<<1<<2<<3; es decir, que debe ser sin crear objeto temporal

+0

Por supuesto que es posible, ¿Tiene una pregunta más específica acerca de cómo escribir sus propias clases y la sobrecarga de operadores? – TJD

+0

¿Por qué desea hacer esto? –

+0

Este es un problema interesante. Según tengo entendido, endl está atada con enrojecimiento. Sin mencionar que el método de sobrecarga del operador tendría que saber algo sobre lo que sucede después de que vuelva a saber dónde pertenece el endl. –

Respuesta

2

Esto es simplemente una variante de Rob's answer, que no utiliza el montón. Es un cambio bastante grande que yo no quiero simplemente cambiar su respuesta, aunque

struct MyCout { 
    MyCout(std::ostream& os = std::cout) : os(os) {} 
    struct A { 
    A(std::ostream& r) : os(r), live(true) {} 
    A(A& r) : os(r.os), live(true) {r.live=false;} 
    ~A() { if(live) {os << std::endl;} } 
    std::ostream& os; 
    bool live; 
    }; 
    std::ostream& os; 
}; 

template <class T> 
MyCout::A& operator<<(MyCout::A& a, const T& t) { 
    a->os << t; 
    return a; 
} 

template<class T> 
MyCout::A operator<<(MyCout& m, const T& t) { return MyCout::A(os) << t; } 

int main() { 
    MyCout mycout; 
    mycout << 1 << 2 << 3; 
    mycout << 3 << 4 << 5; 
    MyCout mycerr(std::cerr); 
    mycerr << 6 << "Hello, world" << "!"; 
} 
+0

¿Puede estar seguro de que la elisión de copia no se producirá en el retorno del 'operador << (MyCout &, const T &)'? –

+1

@Rob: No, pero si lo hice bien, eso no cambia el comportamiento del programa. Yo uso 'bool live' para emular un constructor de movimientos. –

8

Puede utilizar el destructor de un objeto temporal para eliminar la corriente e imprimir una nueva línea. El sistema de depuración de Qt hace esto, y this answer describe cómo hacerlo.

+0

Estaba pensando eso también. Junto con la semántica de movimiento para las operaciones internas. –

+0

Sin embargo, solo puede usar cada objeto para una instrucción de salida, que parece extremadamente subóptimo. –

+0

@Autopulated, sí, sé de esta variante, pero escribí que debe verse de la siguiente manera: 'MyCout mycout; mycout << ... 'es decir, el objeto temporal no es la solución – eXXXXXXXXXXX2

7

las siguientes obras en C++ 11:

#include <iostream> 

struct myout_base { }; 
struct myout 
{ 
    bool alive; 
    myout() : alive(true) { } 
    myout(myout && rhs) : alive(true) { rhs.alive = false; } 
    myout(myout const &) = delete; 
    ~myout() { if (alive) std::cout << std::endl; } 
}; 

template <typename T> 
myout operator<<(myout && o, T const & x) 
{ 
    std::cout << x; 
    return std::move(o); 
} 

template <typename T> 
myout operator<<(myout_base &, T const & x) 
{ 
    return std::move(myout() << x); 
} 

myout_base m_out; // like the global std::cout 

int main() 
{ 
    m_out << 1 << 2 << 3; 
} 

Con más trabajo, se puede agregar una referencia a la corriente de salida actual.

+0

Ahora que es una solución ordenada. – James

+0

¿Es posible usar solo C++ claro?) – eXXXXXXXXXXX2

+4

Sí. I * estoy * usando solo C++ claro :-) –

1

Si es necesario evitar el C++ 11 características:

#include <iostream> 
#include <sstream> 
#include <memory> 

struct MyCout { 
    MyCout(std::ostream& os = std::cout) : os(os) {} 
    struct A { 
    A(std::ostream& os) : os(os) {} 
    A() : os(os) {} 
    ~A() { os << std::endl; } 
    std::ostream& os; 
    }; 
    std::ostream& os; 
}; 

template <class T> 
const std::auto_ptr<MyCout::A>& 
operator<<(const std::auto_ptr<MyCout::A>& a, const T& t) { 
    a->os << t; 
    return a; 
} 

template<class T> 
const std::auto_ptr<MyCout::A> 
operator<<(MyCout& m, const T& t) { 
    std::auto_ptr<MyCout::A> p(new MyCout::A(m.os)); 
    p << t; 
    return p; 
} 

int main() { 
    MyCout mycout; 
    mycout << 1 << 2 << 3; 
    mycout << 3 << 4 << 5; 
    MyCout mycerr(std::cerr); 
    mycerr << 6 << "Hello, world" << "!"; 
} 
+0

Sí, simplemente cree una clase interna y devuélvala por valor en lugar de hacerlo por referencia en el operador << inicial, luego flush/endl en el destructor de ese objeto. Auto crea el objeto temporal por ti. –

+0

@Rob: Esto es lo que haría, excepto que usaría un bool para ver si está vivo en lugar de presionar el asignador. –

+0

@ebyrob: No se puede devolver por valor, ya que podría hacer una copia, y luego eliminar el temporal, causando una descarga adicional. –