2012-09-24 16 views
8

私はロギングシステムのフロントエンドであるC++クラスを持っています。そのロギング機能は、C++ 11の可変引数テンプレートを使用して実装されていますGCCのprintf format属性をC++ 11のバリデーションテンプレートで使用する方法は?

template <typename... Args> 
void Frontend::log(const char *fmt, Args&&... args) { 
    backend->true_log(fmt, std::forward<Args>(args)...); 
} 

各ログのバックエンドは、とりわけ、vsnprintfを呼び出すために、転送パラメータを使用して、こと、true_logの独自のバージョンを実装しています。例:

void Backend::true_log(const char *fmt, ...) { 
    // other stuff.. 
    va_list ap; 
    va_start(ap, fmt); 
    vsnprintf(buffer, buffer_length, fmt, ap); 
    va_end(ap); 
    // other stuff.. 
} 

すべてはうまく動作し、私は満足しています。

ここで、log()パラメータに静的なチェックを追加します。具体的には、GCCのprintf形式属性を使用したいと思います。

私はの機能に__attribute__ ((format (printf, 2, 3)))というタグを付けることから始めました(thisは最初の "隠し"パラメータなので、パラメータインデックスを1つシフトする必要があります)。場合は、コンパイルエラーで失敗したので、これは、動作しません。そして、

error: args to be formatted is not ‘...’ 

、私はtrue_log()関数に同じ属性を追加しようとしました。これはコンパイルされますが、実際にはエラーチェックは行われません。無効な書式/変数の組み合わせをlog()に渡そうとしましたが、警告は発行されませんでした。たぶん、この種のチェックは「遅すぎますか」、言い換えれば、変数に関する情報がコールのチェーンで失われているのでしょうか?

最後に、log()__attribute__ ((format (printf, 2, 0)))と注釈を付けると、間違った書式文字列に関する警告が表示されますが、無効な書式/変数の組み合わせについては診断が発行されません。

問題の概要:C++ 11の可変テンプレートを使用すると、どのようにGCCからフルフォーマットチェックができますか?

+0

vsnprintf()は古い学校よりも多くのことを処理できないため、最初にバリデーショナルテンプレートを気にするのはなぜですか? –

+1

型情報を投げ捨てるときにバリデーションテンプレートを使用しているのはなぜですか?単に 'true_log()'をあなたの本当のロギング関数にしてください。 –

+0

また、 'Frontend :: log'を可変引数にする... –

答えて

2

私はあなたができるとは思わない。 GCCはリテラルの場合にのみフォーマット文字列を検証すると確信しています。このため、true_logformat属性を設定しても機能しません。その関数は、(構文的に)実行時決定文字列のように見えるもので呼び出されます。それをlogに置くと直接回避できますが、可変テンプレートをサポートするには属性がformatである必要があります。

私はより多くのC++形式の出力を行う方法を見てみることをお勧めします。たとえば、boost::formatはprintfと同じように動作しますが、パラメータタイプの数とタイプがフォーマット文字列と一致することを動的に検証します。しかし、バリデーショナルテンプレートを使用するのではなく、(演算子%を使用して)それに供給されるパラメータを1つずつ消費します。

1

記録のために、私はC++ 11バリデーションテンプレートを完全に削除し、伝統的なva_listを使用しました。

__attribute__((format(printf, 2, 3))) 
void Frontend::log(const char *fmt, ...) { 
    va_list ap; 
    va_start(ap, fmt); 
    backend->true_log(fmt, ap); 
    va_end(ap); 
} 

void Backend::true_log(const char *fmt, va_list ap) { 
    // log the message somehow 
} 
関連する問題