【问题标题】:c++ log functions using template SFINAE for conditional compile使用模板 SFINAE 进行条件编译的 c++ 日志函数
【发布时间】: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


【解决方案1】:

正如所写,编译器无法优化

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

【讨论】:

    【解决方案2】:

    实际上,所有这些Log&lt;&gt; 函数都将包含在可执行代码中,除非编译器找不到合适的模板函数重载。在这种情况下,您将收到编译错误。不包含模板函数的唯一情况是它没有在任何地方使用。所以,你的函数调用都不是在 NOOP 中解析的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-10
      • 2020-05-22
      • 1970-01-01
      • 2013-06-24
      • 1970-01-01
      • 2022-01-11
      相关资源
      最近更新 更多