Reputation: 678
I have a variadic template function that takes an indirect function pointer (and its parameters) and invokes it (shown below). I was wondering how to modify this function so that it can have the proper return type matching the indirect function pointer it is invoking?
typedef UINT(APIENTRY *PFNFOO)(UINT, double);
class Foo
{
public:
static UINT APIENTRY pfnFoo(UINT x, double y)
{
return (UINT)(x*y);
}
};
template<typename PFN, typename... ARGS>
inline void CallFunc(void* pfn, const ARGS&... args)
{
reinterpret_cast<PFN>(pfn) (args...);
}
int _tmain(int argc, _TCHAR* argv[])
{
PFNFOO pfn = &Foo::pfnFoo;
CallFunc<PFNFOO>(pfn, 100, 0.5f);
return 0;
}
I tried the following but it complained that error C2782: 'RET CallFunc(RET (__cdecl *)(ARGS...),const ARGS &...)' : template parameter 'ARGS' is ambiguous.
I think I am just missing the proper syntax so I would appreciate help here.
template<typename PFN, typename RET, typename... ARGS>
inline RET CallFunc(RET(*pfn)(ARGS...), const ARGS&... args)
{
return reinterpret_cast<PFN>(pfn) (args...);
}
auto x = CallFunc<PFNFOO>(pfn, 100, 0.5f);
Upvotes: 2
Views: 394
Reputation: 217293
To allow full deduction, you may use the following: (live example)
template<typename Ret, typename... Params, typename...Args>
inline Ret CallFunc(Ret(*pfn)(Params...), Args&&... args)
{
return (*pfn)(std::forward<Args>(args)...);
}
And then call it:
CallFunc(&Foo::pfnFoo, 100, 0.5f); // float will be converted into double in CallFunc.
Upvotes: 3
Reputation: 109149
Your function expects a UINT
and double
as arguments, while you call it with int
and float
, so there is a mismatch between the types of PFNFOO
's arguments, and the actual arguments you pass to CallFunc
. Furthermore, there's no need to specify the function pointer type explicitly, let the compiler deduce it. Your template can be simplified to:
template<typename RET, typename... ARGS>
inline RET CallFunc(RET(*pfn)(ARGS...), ARGS&&... args)
{
return (*pfn)(std::forward<ARGS>(args)...);
}
Usage:
CallFunc(&Foo::pfnFoo, 100U, 0.5);
And if you want to pass it an int
and a float
, just specify the argument types explicitly.
CallFunc<UINT, UINT, double>(&Foo::pfnFoo, 100, 0.5f);
Upvotes: 1