C++ 延迟日志记录(没有 C++11)
C++ Deferred Logging (Without C++11)
目前,我们的代码库中有很多代码如下所示:
void log(int level, const char *msg) {
// logLevel is some global int defining which messages to log
if (level <= logLevel) {
cout << msg << endl;
}
}
...
int someNum = 3;
if (1 <= logLevel) {
char msg[200];
sprintf(msg, "Some format %d", someNum);
log(1, msg);
}
我们使用的是 Visual Studio 2008,因此无法使用 C++11 的任何功能。有没有一种干净的方法可以将闭包传递给日志方法,这样我就可以删除重复的 "if" 条件?例如,我正在寻找与 C++11 之前语法中的以下代码等效的代码:
void log(int level, std::function<std::string ()> getMessage) {
if (level <= logLevel) {
cout << getMessage() << endl;
}
}
...
int someNum = 3;
log(1, [someNum]() -> std::string {
std::ostringstream sstream;
sstream << "Some format " << someNum;
return sstream.str();
});
我能想到的最好的是:
struct LogMessage {
virtual std::string operator()() const = 0;
};
void log(int level, const LogMessage &getMessage) {
if (level <= logLevel) {
cout << getMessage() << endl;
}
}
...
struct X : public LogMessage {
X(int num) : myNum(num) { }
std::string operator()() const {
std::ostringstream out;
out << "Some format " << myNum;
return out.str();
}
private: const int myNum;
} a(someNum);
log(1, a);
即使通常不推荐使用宏,它们在这种特定情况下也会有所帮助,特别是如果您的所有文本都可以由流处理。
将日志函数设为宏:
#define LOG(level, msg) { if (level <= logLevel) { cout << msg << endl; } }
那么,如果你这样做:
LOG( 1, "Some format " << someNum )
if
测试已完成,只有在日志级别条件为 true
.
时,才会执行宏第二个参数中完成的任何复杂格式设置
注意:对于使用 sprintf 的现有行,您仍然需要声明一个函数...:[=15=]
inline std::string printNum( int someNum )
{
char msg[200];
sprintf(msg, "Some format %d", someNum);
return msg;
}
LOG( 1, printNum(3) )
为了补充@jpo38 提供的答案,只需添加另一个宏来接受可变参数以支持 printf
风格的函数:
#define LOGF(LEVEL, ...)\
if ((LEVEL) <= logLevel) {\
char msg[200];\
sprintf(msg, __VA_ARGS__);\
log((LEVEL), msg);\
}
那么以下任一调用都会产生相同的输出:
LOG(1, "Some format " << someNum);
LOGF(1, "Some format %d", someNum);
目前,我们的代码库中有很多代码如下所示:
void log(int level, const char *msg) {
// logLevel is some global int defining which messages to log
if (level <= logLevel) {
cout << msg << endl;
}
}
...
int someNum = 3;
if (1 <= logLevel) {
char msg[200];
sprintf(msg, "Some format %d", someNum);
log(1, msg);
}
我们使用的是 Visual Studio 2008,因此无法使用 C++11 的任何功能。有没有一种干净的方法可以将闭包传递给日志方法,这样我就可以删除重复的 "if" 条件?例如,我正在寻找与 C++11 之前语法中的以下代码等效的代码:
void log(int level, std::function<std::string ()> getMessage) {
if (level <= logLevel) {
cout << getMessage() << endl;
}
}
...
int someNum = 3;
log(1, [someNum]() -> std::string {
std::ostringstream sstream;
sstream << "Some format " << someNum;
return sstream.str();
});
我能想到的最好的是:
struct LogMessage {
virtual std::string operator()() const = 0;
};
void log(int level, const LogMessage &getMessage) {
if (level <= logLevel) {
cout << getMessage() << endl;
}
}
...
struct X : public LogMessage {
X(int num) : myNum(num) { }
std::string operator()() const {
std::ostringstream out;
out << "Some format " << myNum;
return out.str();
}
private: const int myNum;
} a(someNum);
log(1, a);
即使通常不推荐使用宏,它们在这种特定情况下也会有所帮助,特别是如果您的所有文本都可以由流处理。
将日志函数设为宏:
#define LOG(level, msg) { if (level <= logLevel) { cout << msg << endl; } }
那么,如果你这样做:
LOG( 1, "Some format " << someNum )
if
测试已完成,只有在日志级别条件为 true
.
注意:对于使用 sprintf 的现有行,您仍然需要声明一个函数...:[=15=]
inline std::string printNum( int someNum )
{
char msg[200];
sprintf(msg, "Some format %d", someNum);
return msg;
}
LOG( 1, printNum(3) )
为了补充@jpo38 提供的答案,只需添加另一个宏来接受可变参数以支持 printf
风格的函数:
#define LOGF(LEVEL, ...)\
if ((LEVEL) <= logLevel) {\
char msg[200];\
sprintf(msg, __VA_ARGS__);\
log((LEVEL), msg);\
}
那么以下任一调用都会产生相同的输出:
LOG(1, "Some format " << someNum);
LOGF(1, "Some format %d", someNum);