2013-02-02 37 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