2009-03-23 12 views

Respuesta

29
class Log 
{ 
public: 
    Log(const std::string &funcName) 
    { 
     std::cout << funcName << ": "; 
    } 

    template <class T> 
    Log &operator<<(const T &v) 
    { 
     std::cout << v; 
     return *this; 
    } 

    ~Log() 
    { 
     std::cout << " [end of message]" << std::endl; 
    } 
}; 

#define MAGIC_LOG Log(__FUNCTION__) 

Por lo tanto:

MAGIC_LOG << "here's a message"; 
MAGIC_LOG << "here's one with a number: " << 5; 
+0

+1. A diferencia de todas las respuestas que dicen "anular el operador <<()", esta solución resuelve el hecho de que el encabezado y el pie de página deben enviarse una vez por declaración, no una vez por <<. –

+0

+1 de hecho, buena idea. algo sobre endl: sospecho que para un mensaje de depuración, endl rara vez es necesario, pero si quieres << también en el registro mágico, pon un Log & operator << (ostream & (* f) (ostream &)) { cout << * f; devuelve * esto; }. –

+0

@Earwicker. Gracias por tu buena solución. Explique qué significa instanciar una clase sin crear una variable de objeto. Soy nuevo en C++ y nunca he visto esto antes. – jackhab

-1

Usted también podría override the operator. Te permitirá llamar a otra función o prefijo/sufijo cualquier cosa que vaya a dejar el buffer de salida con lo que desees: en tu caso, tendrías que emitir una cadena específica.

+0

-1.Al anular el operador, se generarán un encabezado y un pie de página para cada elemento formateado: p. "new_cout << 1 << 2 << 3;" producirá 3 encabezados y pies de página. –

+0

Sí, mis sugerencias asumen que la persona que está escribiendo la anulación sabe dónde debe hacerse, para qué tipos, y que su código realmente hará uso de ella correctamente. –

0

Tiene que anular el operador < <(), pero incluso no tiene que subclase std :: cout. También puedes crear un nuevo objeto o usar objetos existentes como ese.

1

Además de la respuesta de Mykola, que tienen la siguiente implementación en mi código. El uso es

  LOG_DEBUG("print 3 " << 3); 

impresiones

  DEBUG (f.cpp, 101): print 3 3 

Puede modificarlo para utilizar FUNCIÓN lo largo de/en lugar de LÍNEA y ARCHIVO

/// Implements a simple logging facility. 
class Logger 
{ 
     std::ostringstream os_; 
     static Logger* instance_; 
     Logger(); 
public: 
     static Logger* getLogger(); 
     bool isDebugEnabled() const; 
     void log(LogLevelEnum l, std::ostringstream& os, const char* filename, int lineno) const; 
     std::ostringstream& getStream() 
     { return os_; } 
}; 

void Logger::log(LogLevelEnum l, std::ostringstream& os, const char* filename, int lineno) const 
{ 
     std::cout << logLevelEnumToString(l) << "\t(" << fileName << ": " << lineno << ")\t- " << os.str(); 
     os.str(""); 
} 

#define LOG_common(level, cptext) do {\ 
     utility::Logger::getLogger()->getStream() << cptext; \ 
     utility::Logger::getLogger()->log(utility::level, utility::Logger::getLogger()->getStream(), __FILE__, __LINE__); \ 
} while(0); 

enum LogLevelEnum { 
     DEBUG_LOG_LEVEL, 
     INFO_LOG_LEVEL, 
     WARN_LOG_LEVEL, 
     ERROR_LOG_LEVEL, 
     NOTICE_LOG_LEVEL, 
     FATAL_LOG_LEVEL 
}; 

#define LOG_DEBUG(cptext) LOG_common(DEBUG_LOG_LEVEL, cptext) 
#define LOG_INFO(cptext)  LOG_common(INFO_LOG_LEVEL , cptext) 
#define LOG_WARN(cptext)  LOG_common(WARN_LOG_LEVEL , cptext) 
#define LOG_ERROR(cptext) LOG_common(ERROR_LOG_LEVEL, cptext) 
#define LOG_NOTICE(cptext) LOG_common(NOTICE_LOG_LEVEL, cptext) 
#define LOG_FATAL(cptext) LOG_common(FATAL_LOG_LEVEL, cptext) 

const char* logLevelEnumToString(LogLevelEnum m) 
{ 
     switch(m) 
     { 
       case DEBUG_LOG_LEVEL: 
         return "DEBUG"; 
       case INFO_LOG_LEVEL: 
         return "INFO"; 
       case WARN_LOG_LEVEL: 
         return "WARN"; 
       case NOTICE_LOG_LEVEL: 
         return "NOTICE"; 
       case ERROR_LOG_LEVEL: 
         return "ERROR"; 
       case FATAL_LOG_LEVEL: 
         return "FATAL"; 
       default: 
         CP_MSG_ASSERT(false, CP_TEXT("invalid value of LogLevelEnum")); 
         return 0; 
     } 
} 
2
#define debug_print(message) (std::cout << __FUNCTION__ << (message) << std::endl) 

Esto tiene la ventaja de que se puede desactivar todos los mensajes de depuración a la vez cuando haya terminado

#define debug_print(message)() 
0

Para fines de registro que utilizo algo como

#define LOG(x) \ 
    cout << __FUNCTION__ << x << endl 

// ... 
LOG("My message with number " << number << " and some more"); 

El problema con el enfoque es (como Mykola Golybyew explicó) que FUNCIÓN se procesa en tiempo de compilación y, por lo tanto, siempre imprimiría el mismo nombre con una solución sin preprocesador.

Si es sólo para añadir endl a sus mensajes, usted podría intentar algo como:

class MyLine { 
public: 
    bool written; 
    std::ostream& stream; 
    MyLine(const MyLine& _line) : stream(_line.stream), written(false) { } 
    MyLine(std::ostream& _stream) : stream(_stream), written(false) { } 
    ~MyLine() { if (!written) stream << "End of Message" << std::endl; } 
}; 

template <class T> MyLine operator<<(MyLine& line, const T& _val) { 
    line.stream << _val; 
    line.written = true; 
    return line; 
} 

class MyStream { 
public: 
    std::ostream& parentStream; 
    MyStream(std::ostream& _parentStream) : parentStream(_parentStream) { } 
    MyLine getLine() { return MyLine(parentStream); } 
}; 

template <class T> MyLine operator<<(MyStream& stream, const T& _val) { 
    return (stream.getLine() << _val); 
} 

int main() 
{ 
     MyStream stream(std::cout); 
     stream << "Hello " << 13 << " some more data"; 
     stream << "This is in the next line " << " 1 "; 
    return 0; 
} 

Nota, que es importante no volver referencias de las funciones de operador. Como el MyLine solo debe existir como temporal (para su destructor activa la escritura del endl), el primer objeto (devuelto por la función getLine() en MyStream) se destruirá antes de llamar al segundo operator<<. Por lo tanto, el objeto MyLine se copia en cada operator<< creando uno nuevo. El último objeto se destruye sin que se escriba y escriba el final del mensaje en su destructor.

Simplemente pruébelo en el depurador para comprender qué está pasando ...

Cuestiones relacionadas