8

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

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());

如果 level 小于 global_severity_level,则不调用 create_message。实际上, create_message 可以很长,而且不管它创建什么字符串。如果有很多“调试”日志,那么在非调试模式下运行时,这些日志可能会成为很大的开销。

我知道如果函数“log”是一个宏,则可以这样做,只有在 severity > minimum_severity 时才调用 create_message();但是没有宏就没有另一种方法吗?

编辑

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

log(level, "Created object " + my_object.getName());

在这种情况下,有没有办法以相对透明的方式编写日志而不创建完整的字符串,以便程序员调用日志?

非常感谢

4

4 回答 4

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;
    }
}

然后你会这样称呼它:

log(level, create_message);

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

log(level, [&](){ return "Created object " + my_object.getName(); });

如果您真的不想对参数进行评估(正如您在评论中所描述的那样),那么您需要检查调用之外的级别:

if (level >= global_log_level) {
  log(level, create_message());
}
于 2013-02-02T18:50:44.033 回答
6

类似于@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;
    }
}
于 2013-02-02T19:31:55.820 回答
1

@sftrabbit 答案是首选。但是,如果您不想更改 log(),您可以调用它:

log (level, (level >= global_log_level)? create_message() : "");
于 2013-02-02T18:58:09.767 回答
1

您可以创建一个宏



    #define log(level, message) { \
    if(level >= global_log_level) {\
    cout << message; }}

现在如果你打电话

log(debug, create_message());
仅当调试级别是所需的级别时才会调用 create_message。

于 2013-02-02T19:25:54.040 回答