Wie kann ich eine Klasse von cout
, so dass zum Beispiel ableiten, um es zu schreibenanpassen cout
new_cout << "message";
zu
entsprechen würdecout << __FUNCTION__ << "message" << "end of message" << endl;
Wie kann ich eine Klasse von cout
, so dass zum Beispiel ableiten, um es zu schreibenanpassen cout
new_cout << "message";
zu
entsprechen würdecout << __FUNCTION__ << "message" << "end of message" << endl;
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__)
Daraus folgt:
MAGIC_LOG << "here's a message";
MAGIC_LOG << "here's one with a number: " << 5;
Sie könnten auch override the operator. Es erlaubt Ihnen, eine andere Funktion oder Präfix/Suffix aufzurufen, die den Ausgabepuffer mit dem belassen, was Sie wollen: In Ihrem Fall würde es eine bestimmte Zeichenkette ausgeben.
-1.Das Überschreiben des Bedieners erzeugt eine Kopf- und Fußzeile für jedes formatierte Element: z.B. "new_cout << 1 << 2 << 3;" produziert 3 Kopf- und Fußzeilen. –
Ja, meine Vorschläge gehen von der Person aus, die den Override schreibt, um zu wissen, wo und für welche Art sie ausgeführt werden sollte und dass ihr Code sie tatsächlich korrekt verwendet. –
Sie müssen Operator < <() überschreiben, aber Sie müssen nicht sogar std :: cout ableiten. Sie können auch ein neues Objekt erstellen oder vorhandene Objekte verwenden.
Weitere von Mykola Antwort habe ich die folgende Implementierung in meinem Code. Die Nutzung ist
LOG_DEBUG("print 3 " << 3);
druckt
DEBUG (f.cpp, 101): print 3 3
Sie es ändern können FUNCTION zusammen/anstelle von LINE und FILE
/// 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;
}
}
#define debug_print(message) (std::cout << __FUNCTION__ << (message) << std::endl)
zu verwenden
Dies hat den Vorteil, dass Sie alle Debug-Meldungen auf einmal deaktivieren können, wenn Sie
#define debug_print(message)()
zur Protokollierung fertig sind benutze ich so etwas wie
#define LOG(x) \
cout << __FUNCTION__ << x << endl
// ...
LOG("My message with number " << number << " and some more");
Das Problem mit dem Ansatz (wie Mykola Golybyew erklärte, dass FUNCTION zur Kompilierzeit verarbeitet wird und daher immer den gleichen Namen mit einer Nicht-Präprozessorlösung drucken würde.
Wenn es nur ist Endl, um Ihre Nachrichten für das Hinzufügen, könnten Sie so etwas wie versuchen:
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;
}
Hinweis, dass es nicht zurück Referenzen aus den Bedienfunktionen wichtig ist. Da die MyLine
nur als temporär existieren sollte (denn ihr Destruktor löst das Schreiben der endl
aus), würde das erste Objekt (von der getLine()
Funktion in MyStream
zurückgegeben) zerstört werden, bevor die zweite operator<<
aufgerufen wird. Daher wird das Objekt MyLine
in jedes operator<<
kopiert und ein neues erstellt. Das letzte Objekt wird zerstört, ohne geschrieben zu werden, und hat das Ende der Nachricht in seinem Destruktor geschrieben.
Probieren Sie es einfach im Debugger aus, um zu verstehen, was los ist ...
+1. Im Gegensatz zu allen Antworten, die einfach "override operator <<()" sagen, adressiert diese Lösung die Tatsache, dass die Kopf- und Fußzeile einmal pro Anweisung ausgegeben werden müssen, nicht einmal pro <<. –
+1 in der Tat, nette Idee. nur etwas über endl: Ich vermute für eine Debug-Nachricht, endl wird selten benötigt, aber wenn Sie << in magic log auch sein möchten, setzen Sie ein Log & Operator << (ostream & (* f) (ostream &)) { cout << * f; zurück * dies; }. –
@Earwicker. Danke für deine nette Lösung. Bitte erläutern Sie, was es bedeutet, eine Klasse zu instanziieren, ohne eine Objektvariable zu erstellen. Ich bin neu in C++ und habe das noch nie zuvor gesehen. – jackhab