使用C++进行延迟日志记录

GHL*_*GHL 8 c++ logging lazy-evaluation

让我们假设我们有几个级别的日志记录:跟踪,调试,信息,错误.我想知道是否有办法编写以下代码:

enum log_level = {trace, debug, info, error};

log_level global_log_level = info;

void log(log_level level, string& message){
    if (level >= global_log_level){
        std::cout << message << std::endl;
    }
}

string create_message(){
    ...
}

log_level level = debug;
log (level, create_message());
Run Code Online (Sandbox Code Playgroud)

如果level小于global_severity_level,则不调用create_message.实际上,create_message可能很长,无论它创建一个字符串.如果存在大量"调试"日志,那么在非调试模式下运行时,这些日志会成为一个巨大的开销.

我知道如果函数"log"是一个宏,那么可以这样做,只有当severity> minimal_severity时才调用create_message(); 但没有宏,没有另一种方法可以做到这一点吗?

编辑

在上面,我没有指定create_message,因为它可以是任何东西,特别是:

log(level, "Created object " + my_object.getName());
Run Code Online (Sandbox Code Playgroud)

在这种情况下,是否有一种方法来编写日志,以便以相对透明的方式为程序员调用日志创建完整的字符串?

非常感谢

Jos*_*eld 6

有几种选择.一个有趣的是create_message作为a 传递std::function<std::string()>并从内部调用它log:

void log(log_level level, std::function<std::string()> message_creator){
    if (level >= global_log_level){
        std::cout << message_creator() << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你会这样称呼它:

log(level, create_message);
Run Code Online (Sandbox Code Playgroud)

如果将它们包装在lambda中,这可以使用任意表达式作为参数:

log(level, [&](){ return "Created object " + my_object.getName(); });
Run Code Online (Sandbox Code Playgroud)

如果你真的不想参数被评估(正如你在评论中描述的那样),那么你需要检查通话之外的级别:

if (level >= global_log_level) {
  log(level, create_message());
}
Run Code Online (Sandbox Code Playgroud)

  • 使`log`成为模板,然后编译器应该能够内联lambda. (3认同)
  • lambda是一个轻量级类型,它有自己的`operator()`.`std :: function`是一个复杂的类型 - 擦除怪物,它的创建成本高,而且调用成本高.如果`log`采用lambda对象,则可以省略创建(因为编译器知道它是无状态的),并且可以内联operator(),从而提供全速.这对stdlib中的许多算法也很有用. (2认同)

Sco*_*ham 5

与@sftrabbit类似,但正如@ipc所建议的那样.

使用模板来避免std :: function机制,编译器可能能够内联这个,因此希望最终会更快.

template< typename F >
void log(log_level level, F message_creator){
    if (level >= global_log_level){
        std::cout << message_creator() << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)