2010-12-11 4 views
3

Betrachten Sie die folgende Wrapper um Runtime Dynamic Linking Mechanismus Win32:Wie kann ich (zur Kompilierzeit) feststellen, ob ein Typname ein Funktionszeiger Typname ist?

#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_); 
     } 
    }; 
} 

Und ein Beispiel Client:

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

Grundsätzlich würde Ich mag eine Fehlermeldung hinzufügen, wenn jemand zu verwenden GetFunction versucht, wo T ist alles andere als eine Funktion Zeigertyp (weil die reinterpret_cast ich hier gezwungen bin, könnte sonst Benutzerfehler verstecken).

Graben durch Boost Typ Eigenschaften, ich habe festgestellt, dass es eine bestehende is_function Vorlage gibt. is_function akzeptiert jedoch Verweise auf Funktionen, was in meinem Fall ein Benutzerfehler wäre (Funktion Zeiger nur). Wie kann ich RuntimeDynamicLinker::GetFunction<T>() ändern, um eine verständliche Compiler-Fehlermeldung zu erzeugen, wenn T kein Funktionszeigertyp ist?

(Randbemerkung: Ich habe nie irgendeine Art von TMP getan, also keine Angst, über Dinge zu gehen, die „Basis“, um regelmäßige Nutzer von TMP) sind

Antwort

5

Greifen Sie is_pointer<T>::value && is_function<remove_pointer<T>::type>::value in einem static_assert/BOOST_STATIC_ASSERT nutzen könnten.

+0

+1, weil dies genau das zu tun scheint, was ich brauche. (obwohl warten, um zu sehen, ob es zuerst andere Antworten gibt) –

+0

+1, und werden diese Merkmale in C++ 0x verfügbar sein? –

+0

+1 weil [gemäß der Boost-Dokumentation erkennt man, ob ein Typ ein Funktionszeiger ist] (http://www.boost.org/doc/libs/1_45_0/libs/type_traits/doc/html/boost_typetraits/ Referenz/is_function.html). –

2

Ich glaube, Sie einen Trait verwenden könnten Klasse.

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

typedef void (*MyFunctionPointer)(); 

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

Dies ist die Grundidee einer Trait class.

EDIT: ich werde ein paar Artikel Link für die Einführung von Merkmalen. personnally nahm es für mich einige Zeit, bevor sie :-)

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

+0

+1 weil dies funktionieren würde, aber es funktioniert nicht in meinem speziellen Fall, weil dann würde ich jeden möglichen Funktion Zeigertyp im Voraus definieren muß, was für unzumutbar etwas so groß wie win32. –

+0

Obwohl ich nehme an, dass Sie IsFunctionPointer verwenden können, verwenden Sie den Enum-Hack, um meine "Zur Kompilierzeit" -Anforderung zu erfüllen. –

+0

Ok, alle möglichen Funktionen ... hmm ... was meinst du mit dem Enum-Hack? –

2

können Sie boost::enable_if verwenden wie so:

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) 
{ 
    .... 
} 

Dies wird nur ein Template-Parameter ermöglichen, dass ein Zeiger ist und auch eine Funktion. Alles andere wird zur Kompilierzeit nicht an die Funktion gebunden.

so dass:

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

+1, weil dieser den Typnamen hat, den du für 'remove_pointer' brauchst. –

+0

+1 weil [gemäß der Boost-Dokumentation das ist, wie Sie feststellen, ob ein Typ ein Funktionszeiger ist] (http://www.boost.org/doc/libs/1_45_0/libs/type_traits/doc/html/boost_typetraits/ Referenz/is_function.html). –