How can I (at compile time) determine if a typename is a function pointer typename?

丶灬走出姿态 提交于 2019-12-13 14:18:43

问题


Consider the following wrapper around Win32's Runtime Dynamic Linking mechanism:

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

And an example 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");

Basically, I'd like to add an error message if anyone tries to use GetFunction where T is anything other than a function pointer type (because the reinterpret_cast I'm forced to use here could otherwise hide user errors).

Digging through boost type traits, I did find that there's an existing is_function template. However, is_function accepts references to functions, which would be a user error in my case (function pointers only).

How can I modify RuntimeDynamicLinker::GetFunction<T>() to produce a reasonably understandable compiler error message if T is not a function pointer type?

(Side note: I've never done any kind of TMP, so don't be afraid to go over things that are "basic" to regular users of TMP)


回答1:


You could use is_pointer<T>::value && is_function<remove_pointer<T>::type>::value in a static_assert/BOOST_STATIC_ASSERT.




回答2:


I think you could use a Trait class.

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

typedef void (*MyFunctionPointer)();

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

this is the basic idea of a Trait class.

EDIT: i will ad a few articles link for introducing traits. personnally It took some time for me before grasping them :-)

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




回答3:


You can use boost::enable_if like 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)
{
   ....
}

This will only allow a template parameter that is a pointer and also a function. Anything else will not bind to the function at compile time.

So that:

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


来源:https://stackoverflow.com/questions/4416144/how-can-i-at-compile-time-determine-if-a-typename-is-a-function-pointer-typena

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!