c ++日志函数使用模板SFINAE进行条件编译

时间:2014-08-17 19:41:19

标签: c++ templates c++11 logging sfinae

我正在评估是否可以利用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?字符串是否存在于代码中?

这种做法是个坏主意吗?

2 个答案:

答案 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中解析。