2012-02-28 8 views
2

Windows APIをラッピングしています。エラーチェックを使いやすくして便利です。現在、グローバルエラーオブジェクトがあり、新しいエラーを処理するための関数setがあります。 set関数は4つの引数をとります:bool Error::set (const int code, const char * file, const char * const function, const int line);この関数は、ファイル、関数、およびライン引数を使用して、きれいにフォーマットされたメッセージでそれらを表示します。任意のAPI関数をラップする

エラーの設定を簡単にするために、を使用して、そのAPI関数を呼び出した後にAPI関数が設定したエラーにいつでも対応することができます。setError()

残念ながら、これはこのような何かを探すために、コードが発生します。

SomeAPIFunction(); 
setError(); 
AnotherAPIFunction(); 
setError(); 

コンストラクタに問題もあります:あなたはメンバー初期化子の構文を使用して、見ることができるように

MyClass:MyClass() 
    : a (SomeAPIFunction), b (AnotherAPIFunction) 
{ 
    setError(); //what if both functions set an error? 
} 

は、私は、実際に自分自身を制限しています。この問題を解決するために

一つの方法は、すべてのAPI関数をラップすることです:エラーメッセージの

int someAPIFunction() 
{ 
    int ret = SomeAPIFunction(); 
    setError(); 
    return ret; 
} 

function部分はエラーを発信した機能を教えます。もちろん、それはこれを処理する最悪の可能な方法でなければなりません。

解決策は、variadicテンプレートを使用することです。問題は、私は彼らがこれのために働くようにするために何をすべきか分かりません。私は、最終的なコードは次のいずれかのようになります想像:

wrap<int, SomeAPIFunction (5)>(); 
wrap<int, SomeAPIFunction, 5>(); 
wrap<int, SomeAPIFunction> (5); 

私は可変引数テンプレートを始める上で物事を読んだが、彼らはすべてこのようなものを設定する方法の無知を私に残してきました。誰かが私を正しい方向に向けることができますか?

私はa similar questionで次のが見つかりました:

#include <iostream> 

template<void f(void)> 
struct Wrap { 
    void operator()() const { 
     std::cout << "Pre call hook" << std::endl; 
     f(); 
    } 
}; 

namespace { 
    void test_func() { 
     std::cout << "Real function" << std::endl; 
    } 
} 

const Wrap<&test_func> wrapped_test_func = {}; 

int main() { 
    wrapped_test_func(); 
    return 0; 
} 

回答者は、可変長引数テンプレートが十分にこれが一般的なようにする必要だろうと指摘しました。それは始まりですが、私は迷っていますし、この問題の助けに感謝しています。

+0

はじめに、すべてのAPI関数がGetLastErrorメカニズムを使用しているわけではありません。そして、さらに厄介なことに、これらのAPI関数が失敗を報告したときにGetLastErrorを呼び出すことは有効です。あなたの質問のコードは失敗するように運命づけられています。 –

+0

ほとんどのWin32 API関数は実際にエラーがあった場合にのみ 'LastError'値*を設定します。成功の場合、彼らは 'LastError'値だけを残します。これには例外があります。 Win32 APIのドキュメントでは、各関数が何をしているかについて正確に説明しています。 –

+0

私はそれを認識しています。 'GetLastError'が0(ERROR_SUCCESS)を返した場合、それは無視されます。私は、他のメカニズムも使用しているパーツを知っていますが、私はそれらのサポートをまだ追加していません。私が拡大し続けると、必要なものを追加します。次のAPI関数呼び出しに備えて処理を終えたときに 'SetLastError(0);'を呼び出すことも可能です。 – chris

答えて

1

は、私はあなたが、それはこの構文で動作させることができるでしょうと思う:キーは彼らがかなり厄介いるので、テンプレート型のパラメータを決定するために、コンパイラの使用の型推論をさせることです

wrap(&SomeAPIFunction, arg1, arg2); 

急いで。

コードのようなものになります。当然のことながら、あなたは、アドレスの機能オペレータを非表示にするマクロを使用したい関数名を格納する文字列化を使用し、ファイル名を格納します

template<typename TRet, typename... TArgs> 
TRet wrap(TRet(WINAPI *api)(TArgs...), TArgs... args) 
{ 
    return api(args...); 
} 

を行番号もすべてのものを実際のvariadic関数に渡します。そのためには、バリデーショナルなマクロが必要です。実際には、バリデーショナルなマクロだけで、テンプレートはまったくないのですか?

+0

これはすばやく見えるように見え、使いやすくなっているようです。私は試してみます。 – chris

+0

私はこれを試しました。 'std :: forward()'や '(int&)'や宣言されていないものについては他の形式で問題があるようです。私はそれを少しでも試してみましたが、何も得られませんでした。私はコンパイラが&実際にはどちらかを必要とするとは思わない、私は関数の引数のためにそれを置く必要はありません。 variadicマクロについては、うまくいくと思います。すべてのより複雑なテンプレートの急いで、私はそのオプションを忘れていた。 – chris

+1

@chris:C互換APIを呼び出すときに完璧な転送が必要ないのは間違いありません。ですから 'std :: forward'とrvalue-referenceを削除してください。 –

関連する問題