Как я могу (во время компиляции) определить, является ли имя типа указателем функции? - PullRequest
3 голосов
/ 11 декабря 2010

Рассмотрим следующую оболочку вокруг механизма динамического связывания Win32:

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

И пример клиента:

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

В принципе, я хотел бы добавить сообщение об ошибке, если кто-нибудьпытается использовать GetFunction, где T - это что-то отличное от типа указателя на функцию (потому что reinterpret_cast, который я вынужден использовать здесь, может скрыть ошибки пользователя).

Копать черты типа наддува,Я обнаружил, что существует шаблон is_function.Однако is_function принимает ссылки на функции, что в моем случае было бы ошибкой пользователя (только функция указатели ).

Как изменить RuntimeDynamicLinker::GetFunction<T>(), чтобы получить достаточно понятный компиляторсообщение об ошибке, если T не является указателем на тип функции?

(Примечание: я никогда не делал TMP, поэтому не бойтесь переходить от «базовых» к обычным вещам).пользователи TMP)

Ответы [ 3 ]

5 голосов
/ 11 декабря 2010

Вы можете использовать is_pointer<T>::value && is_function<remove_pointer<T>::type>::value в static_assert / BOOST_STATIC_ASSERT.

2 голосов
/ 11 декабря 2010

Вы можете использовать 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
2 голосов
/ 11 декабря 2010

Я думаю, вы могли бы использовать класс Черты.

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

typedef void (*MyFunctionPointer)();

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

это основная идея класса Черты .

РЕДАКТИРОВАТЬ: я добавлю ссылку на несколько статей для введения черт. лично мне потребовалось некоторое время, чтобы понять их: -)

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

...