Template deduction not working for function pointer reference

帅比萌擦擦* 提交于 2019-12-08 01:31:23

There are two problems with your code. Let's fix them in order.

First, the bodies and return types of the two fnPtrToVoidPtr overloads have to be switched. What you want is to convert lvalues of function pointer type to lvalues of type void*, through the (void*&) cast, so this cast should go in the body of the function taking a * & - this is the parameter type that will bind to modifiable lvalues, the other one, * && will bind to rvalues. Conversely, the (void*) cast has to go into the function taking a * &&. Obviously, the return types need to be changed accordingly.

Now, the reason for the deduction failure: when making a call like fnPtrToVoidPtr(DestroyIcon) in your original version, you're relying on the function-to-pointer conversion. This conversion doesn't happen if the parameter (destination) is a reference.

So, in your second version, where both overloads take references, the parameters are references to pointers, but the argument is a function identifier; template arguments for the former cannot be deduced from the latter, so deduction fails. The simplest fix for this one is to explicitly provide a function pointer for the call, like this: fnPtrToVoidPtr(&DestroyIcon).

&DestroyIcon is an rvalue, so the * && parameter will bind to it, * & won't, exactly what we want.

With these two fixes, a compilable version of your code becomes:

#include "windows.h"

// Cast a function pointer to a void *
template <typename RET_TYPE, typename...ARGs>
void* fnPtrToVoidPtr(RET_TYPE(WINAPI * && pOriginalFunction)(ARGs...))
{
   return (void*)pOriginalFunction;
}

// Cast a function pointer that is referencable to a void *&
template <typename RET_TYPE, typename...ARGs>
void*& fnPtrToVoidPtr(RET_TYPE(WINAPI * & pOriginalFunction)(ARGs...))
{
   return (void*&)pOriginalFunction;
}

BOOL(WINAPI *pDestroyIcon)(HICON) = DestroyIcon;

int main()
{
   void* p1 = fnPtrToVoidPtr(&DestroyIcon);
   void** p2 = &fnPtrToVoidPtr(pDestroyIcon);
}

If you don't like having to use the & operator in front of function names, you can also change the overload taking a * && to take a & - an lvalue reference to a function. Now, that version can be called as fnPtrToVoidPtr(DestroyIcon). A && (rvalue reference to function) will work too, since rvalue references to functions bind to function lvalues as well (all identifier expressions designating functions are lvalues).

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