【发布时间】:2014-08-17 19:41:18
【问题描述】:
我正在评估是否可以利用 C++11 功能来替换日志记录宏,而无需任何运行时额外成本。
我做了这个演示:
enum class LogLevel {
Fatal = 0,
DFatal = 1,
Error = 2,
Normal = 3,
Verbose = 4,
Debug = 5
};
constexpr LogLevel log_compiled = LogLevel::Normal;
LogLevel log_runtime = LogLevel::Error;
#ifdef NDEBUG
constexpr LogLevel log_fatal = LogLevel::Fatal;
#else
constexpr LogLevel log_fatal = LogLevel::DFatal;
#endif
template <LogLevel L, typename std::enable_if<(L <= log_fatal)>::type* = nullptr>
void Log(std::string message) {
std::cout << "Fatal level: " << (int) L << " Message: " << message << std::endl;
exit(0);
}
template <LogLevel L, typename std::enable_if<(L>log_fatal && L <= log_compiled)>::type* = nullptr>
void Log(std::string message) {
if (L <= log_runtime) {
std::cout << "Level: " << (int) L << " Message: " << message << std::endl;
}
}
template <LogLevel L, typename std::enable_if<(L > log_compiled)>::type* = nullptr>
void Log(std::string message) {
}
int main(int argc, char *argv[]) {
//not compiled
Log<LogLevel::Verbose>("Something to much usual");
//compiled, not printed
Log<LogLevel::Normal>("Something usual");
//compiled, printed
Log<LogLevel::Error>("No disk space");
//compiled, printed, terminate in Debug mode
Log<LogLevel::DFatal>("Unexpected contition, recoverable");
//compiled, printed, terminate always
Log<LogLevel::Fatal>("Unexpected contition, unrecoverable");
return 0;
}
这样,我以非常一致的方式处理编译时排除、运行时日志级别和致命条件。
它可能适用于带有
我的问题:
//not compiled
Log<LogLevel::Verbose>("Something to much usual");
这实际上会导致大多数编译器出现 NOOP 吗?字符串会不会存在于代码中?
这种方法是个坏主意吗?
【问题讨论】:
-
不,
std::string的构造函数/析构函数可能有副作用,因此编译器无法省略。如果您担心,请改用const char *,它应该被优化出来。 -
没有回答您的问题,但我一直想知道从发送给用户的二进制文件中删除日志记录的用处。您在最需要它们的地方剥夺了自己的日志消息,因为您无法在客户的机器上运行调试器,您只能让他们向您发送日志。
-
在某些例程(例如 DSP)中,日志记录代码会延迟执行超过 Universe 的剩余寿命。在大多数情况下,它应该被编译,当然。
标签: c++ templates c++11 logging sfinae