2013-02-02 18 views
8

いくつかのレベルのロギングがあるとします。トレース、デバッグ、情報、エラーです。レベルがそのglobal_severity_level小さい場合create_messageなし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はかなり長くても、文字列を作成しても関係ありません。多くの "デバッグ"ログがある場合、それらは非デバッグモードで実行すると相当なオーバーヘッドになる可能性があります。

"log"関数がマクロの場合は、そうすることが可能です。severity> minimal_severityの場合のみcreate_message()を呼び出します。マクロなしでこれを行う別の方法はありませんか?上記で

EDIT

、それは何でもかまいませんので、私は特に、create_messageが指定されていませんでした。この場合

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

を、そのようなログ書き込みをするが方法です。プログラマがログを呼び出すために、完全な文字列が比較的透明な方法で作成されていないことを確認します。

感謝

+0

'create_message()'に 'global_log_level'をチェックさせることができます。 – NPE

+0

'log()'に 'create_message'関数を渡すことができますので、' log() 'はレベルが適切な場合にのみ高価なメッセージを作成しますか? – JaredC

+0

こんにちは、メッセージはどこから来ても構いませんが、log(level、 "Object" + "my_object.getName()+"が作成されたように、その場で書くことができるので、未定義の関数create_message() ; - その場合、私は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自分の答えを考えなかったので+1 :D – ipc

+0

アイデアをお寄せいただき、+ 1'ing。 :) –

6

いくつかの選択肢があります。あなたはそのようにそれを呼ぶだろうその後

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

これは、引数として任意の式で作業することができ、興味深い1はstd::function<std::string()>としてcreate_messageを渡し、logの中からそれを呼び出すことですそれらはラムダの中で:

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'をテンプレートにすると、コンパイラはラムダをインライン化できるはずです。 – ipc

+0

@ Nawaz:この場合、呼び出しを0パラメータのラムダにラップします。 – ybungalobill

1

@sftrabbit回答が推奨されます。しかし、あなたは)(ログを変更したくないだけならば、あなたはそれを呼び出すことができます。

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

確かに、これは三項演算子については考えていませんでした...しかし、ログの呼び出し元がロガーの内部と変数global_log_levelの存在を認識していないとどうなりますか? – GHL

+0

@GHL次に、この構造体をマクロに変換します。ちょっと円形、ええ;-) – paddy

+0

はい、確かに、しかし、行うでしょう:) – GHL

1

あなたは今、あなたは

log(debug, create_message());
create_messageは、デバッグレベルがある場合にのみ呼び出されます呼び出した場合はマクロ



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

を作成することができます希望のもの。

+1

ありがとう、しかし、ポイントは、ログをマクロにする代わりに見つけることでした... – GHL

+0

なぜ、マクロはあなたにとって悪い選択ですか? – strannik

+1

私の意見では、これはC++ 11より前のベスト・ソリューションです。 – ipc