2010-12-11 5 views
3

は、Win32のランタイムダイナミックリンク機構の周りに、次のラッパーを考えてみましょう:コンパイル時に、型名が関数型typenameであるかどうかをどのように判断できますか?

#include <boost/noncopyable.hpp> 
#include <windows.h> 
#include "Exception.hpp" 

namespace WindowsApi 
{ 
    class RuntimeDynamicLinker : boost::noncopyable 
    { 
     HMODULE hMod_; 
    public: 
     RuntimeDynamicLinker(const wchar_t * moduleName) 
     { 
      hMod_ = LoadLibraryW(moduleName); 
      if (hMod_ == 0) 
      { 
       Exception::Throw(GetLastError()); 
      } 
     } 
     template <typename T> 
     T GetFunction(const char* functionName) 
     { 
      FARPROC result = GetProcAddress(hMod_, functionName); 
      if (result == 0) 
      { 
       Exception::Throw(GetLastError()); 
      } 
      return reinterpret_cast<T>(result); 
     } 
     ~RuntimeDynamicLinker() 
     { 
      FreeLibrary(hMod_); 
     } 
    }; 
} 

そして、たとえばクライアント:誰もがGetFunction場所を使用しようとした場合

typedef NTSTATUS (NTAPI * NtQueryInformationProcess_t)(
    IN HANDLE, 
    IN PROCESS_INFORMATION_CLASS, 
    OUT PVOID, 
    IN ULONG, 
    OUT PULONG); 
RuntimeDynamicLinker ntdll(L"ntdll.dll"); 
NtQueryInformationProcess_t NtQueryInformationProcess = 
    ntdll.GetFunction<NtQueryInformationProcess_t>("NtQueryInformationProcess"); 

基本的に、私はエラーメッセージを追加したいですTは、関数ポインタ型以外のものです(なぜなら、私がここで強制的に使用するreinterpret_castはユーザエラーを隠す可能性があるからです)。

ブースト型形質を掘り起こすと、既存のis_functionテンプレートが見つかった。しかし、is_functionは関数への参照を受け入れます。私の場合はユーザエラーです(関数ポインタのみ)。

RuntimeDynamicLinker::GetFunction<T>()を修正して、Tが関数ポインタ型でない場合、合理的に理解できるコンパイラエラーメッセージを生成するにはどうすればよいですか?

(サイドノート:私はTMPのいずれかの種類をやったことがないので、TMPの通常のユーザーに「基本」です物事の上に行くことを恐れてはいけません)私はあなたが形質を使うことができると思い

答えて

5

:-)それらを把握する前に、私のために少し時間がかかりました。

+0

+1これは私が必要とするものを正確に行うように思われるためです。 (最初に他の答えがあるかどうかを確認するのを待っていますが) –

+0

+1、これらの特性はC++ 0xで利用できますか? –

+0

+1 [Boostの文書によれば、これはタイプが関数ポインタであるかどうかを検出する方法です](http://www.boost.org/doc/libs/1_45_0/libs/type_traits/doc/html/boost_typetraits/ reference/is_function.html)。 –

2

クラス。

template <typename T> 
class IsFunctionPointer 
{ 
public: 
    bool isFunctionPointer(){return false;}; 
} 

typedef void (*MyFunctionPointer)(); 

template <> 
class IsFunctionPointer<MyFunctionPointer> 
{ 
public: 
    bool isFunctionPointer(){return true;}; 
} 

これはTrait classの基本的な考え方です。

編集:私は、形質を導入するためのいくつかの記事のリンクを広告します。 personnallyそれはあなたがstatic_assert/BOOST_STATIC_ASSERTis_pointer<T>::value && is_function<remove_pointer<T>::type>::valueを使用することができ

http://accu.org/index.php/journals/442

+0

+1、これは動作しますので、その後私がのために不合理である、事前に可能なすべての関数ポインタ型を定義する必要があると思いますので、それは私の特定のケースでは動作しません。 win32ほど大きいもの。 –

+0

私は "コンパイル時"の要件を満たすために、isFunctionPointerにenumハックを使用させることができます。 –

+0

オク、すべての可能な機能...うーん... enumのハックはどういう意味ですか? –

2

あなたはそうのようなboost::enable_ifを使用することができます。

template <typename T> 
T GetFunction(const char* functionName, 
    typename boost::enable_if_c<boost::is_pointer<T>::value 
     && boost::is_function<typename boost::remove_pointer<T>::type>::value>::type* = 0) 
{ 
    .... 
} 

これが唯一のポインタと、関数であるテンプレートパラメータを許可します。他のものはコンパイル時に関数にバインドされません。

だから:

GetFunction<int(*)()>("foo"); // compiles properly 
GetFunction<int()>("foo"); // fails to compile 
+0

+1これは 'remove_pointer'に必要な' typename'を持っているためです。 –

+0

+1 [Boostの文書によれば、タイプが関数ポインタであるかどうかを検出する方法です](http://www.boost.org/doc/libs/1_45_0/libs/type_traits/doc/html/boost_typetraits/ reference/is_function.html)。 –

関連する問題