2013-02-02 36 views
8

假设我们有几个级别的日志记录:trace,debug,info,error。 我想知道是否有写下面的代码的方式:C++中的懒惰日志记录

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

没有create_message被称为如果级别为越小global_severity_level。事实上,create_message可能会很长,并且不管它创建了什么字符串。如果有很多“调试”日志,那么在非调试模式下运行时,这些日志可能会产生大量开销。

我知道如果函数“log”是一个宏,可以这样做,只有在severity> minimal_severity;时才调用create_message()。但没有另外一种方法可以在没有宏的情况下执行此操作?

编辑

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

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

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

非常感谢

+0

你可以'create_message()'检查'global_log_level'。 – NPE

+0

您可以将'create_message'函数传递给'log()',所以'log()'只会在级别合适的情况下生成昂贵的消息? – JaredC

+0

你好,我指的是一个未指定的函数create_message(),因为这个消息可能来自任何地方,但它可以在运行时写入,就像log(level,“Object”+ my_object.getName()+“已被创建”)。 ; - 在这种情况下,我无法将任何内容传递给create_message(),它基本上是2个字符串之间的运算符+。我也不能将此函数作为函数传递到日志中... – GHL

回答

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

+1因为我没有时间对我的答案进行更改:D –

+0

+1,因为我没有想过自己做出答案:D – ipc

+0

感谢您的想法和+ 1。 :) –

6

有几种选择。一个有趣的一个是通过create_message作为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); 

这可以用任意表达式工作作为参数,如果你换他们在一个拉姆达:

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

如果你真的不想参数进行评估(正如你在commen中所描述的ts),那么你需要检查电话以外的级别:

if (level >= global_log_level) { 
    log(level, create_message()); 
} 
+0

用'[&]替换'[]'。另外,如果create_message是任何采用某些参数的任意函数呢?这似乎不足以延迟创建消息的功能;推迟函数论证本身的评估似乎也是合乎逻辑的。 log函数如何知道这些参数又是另一个问题。 – Nawaz

+3

使'log'成为一个模板,然后编译器应该能够内联lambda。 – ipc

+0

@Nawaz:在这种情况下,您将调用包装为零参数lambda。 – ybungalobill

1

@sftrabbit答案是首选。只是如果你不想改变日志(),你可以把它叫做:

log (level, (level >= global_log_level)? create_message() : ""); 
+0

事实上,这是有效的,没有考虑三元运算符......但是如果log的调用者不知道记录器的内部以及变量global_log_level的存在性怎么办? – GHL

+0

@GHL然后你把这个构造变成一个宏。有点圆形,呃;-) – paddy

+0

是的确,但会做:) – GHL

1

您可以创建一个宏



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

现在,如果你调用

log(debug, create_message());
create_message只被调用,如果调试级别所需的一个。

+1

谢谢,但重点是找到一个替代品,使日志宏... – GHL

+0

只是好奇,为什么宏是一个坏的选择吗? – strannik

+1

在我看来,这是C++ 11之前的最佳解决方案。 – ipc