personnaliser cout

Comment puis-je dériver une classe de cout pour que, par exemple, y écrire

new_cout << "message";

serait équivalent à

cout << __FUNCTION__ << "message" << "end of message" << endl;

 class Log { public: Log(const std::ssortingng &funcName) { std::cout << funcName << ": "; } template  Log &operator<<(const T &v) { std::cout << v; return *this; } ~Log() { std::cout << " [end of message]" << std::endl; } }; #define MAGIC_LOG Log(__FUNCTION__) 

Par conséquent:

 MAGIC_LOG << "here's a message"; MAGIC_LOG << "here's one with a number: " << 5; 
 #define debug_print(message) (std::cout << __FUNCTION__ << (message) << std::endl) 

Cela a l'avantage que vous pouvez désactiver tous les messages de débogage à la fois lorsque vous avez terminé

 #define debug_print(message) () 

Plus loin de la réponse de Mykola, j’ai l’implémentation suivante dans mon code. L’usage est

  LOG_DEBUG("print 3 " << 3); 

empreintes

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

Vous pouvez le modifier pour utiliser FUNCTION avec / à la place de LINE et FILE

 /// Implements a simple logging facility. class Logger { std::ossortingngstream os_; static Logger* instance_; Logger(); public: static Logger* getLogger(); bool isDebugEnabled() const; void log(LogLevelEnum l, std::ossortingngstream& os, const char* filename, int lineno) const; std::ossortingngstream& getStream() { return os_; } }; void Logger::log(LogLevelEnum l, std::ossortingngstream& 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* logLevelEnumToSsortingng(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; } } 

Vous devez écraser l’opérateur << (), mais vous n'avez même pas à sous-classer std :: cout. Vous pouvez également créer un nouvel objet ou utiliser des objets existants comme cela.

J’utilise quelque chose comme:

 #define LOG(x) \ cout << __FUNCTION__ << x << endl // ... LOG("My message with number " << number << " and some more"); 

Le problème de votre approche est (comme l'explique Mykola Golybyew) que FUNCTION est traité au moment de la compilation et que, par conséquent, le même nom sera toujours imprimé avec une solution sans préprocesseur.

Si c'est uniquement pour append endl à vos messages, vous pouvez essayer quelque chose comme:

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

Notez qu'il est important de ne pas renvoyer de références depuis les fonctions de l'opérateur. Etant donné que MyLine ne doit exister que temporairement (son destructeur déclenche l'écriture de l' endl ), le premier object (renvoyé par la fonction getLine() dans MyStream ) sera détruit avant l'appel du deuxième operator<< . Par conséquent, l'object MyLine est copié dans chaque operator<< créant un nouvel. Le dernier object est détruit sans être écrit et écrit la fin du message dans son destructeur.

Essayez simplement dans le débogueur pour comprendre ce qui se passe ...

Vous pouvez également remplacer l’opérateur . Cela vous permettra d’appeler une autre fonction ou un préfixe / suffixe pour tout ce qui va quitter le tampon de sortie avec ce que vous voulez: dans votre cas, vous voudriez qu’il affiche une chaîne spécifique.