我正在评估是否可以利用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;
}
这样我就以非常一致的方式处理编译时排除,运行时日志级别和致命条件。
它可能适用于具有&lt;&lt;&lt;&lt;&lt;操作
我的问题:
//not compiled
Log<LogLevel::Verbose>("Something to much usual");
这实际上是否会导致大多数编译器的NOOP?字符串是否存在于代码中?
这种做法是个坏主意吗?
答案 0 :(得分:2)
如上所述,编译器无法优化
Log<LogLevel::Verbose>("Something to much usual");
因为它会构造然后破坏std::string
,这可能会产生副作用(例如,使用可能被替换的::operator new
和::operator delete
分配然后释放内存。)
但是,如果您编写Log
模板以取代const char *
,则可以完全优化呼叫。给定
template <LogLevel L, typename std::enable_if<(L > log_compiled)>::type* = nullptr>
void Log(const char * ) {
}
int main() {
Log<LogLevel::Verbose>("Something to much usual");
return 0;
}
g ++ 4.9在-O2
compiles it只是
xorl %eax, %eax
ret
答案 1 :(得分:-1)
实际上,所有这些Log<>
函数都将包含在可执行代码中,除非编译器无法找到适当的模板函数重载。在这种情况下,您将收到编译错误。不包含模板功能的唯一情况是在任何地方都不使用它。所以,你的函数调用在NOOP中解析。