Metaprogramming Approach. First, some pointers that try to store call information:
template<class...>types {using type=types;}; enum class calling_convention { cdecl, clrcall, stdcall, fastcall, thiscall, vectorcall, }; template<class Sig> struct signature_properties; template<class R, class...Args> struct signature_properties { using return_type = R; using argument_types = types<Args...>; }; template<class FuncPtr> struct function_properties; #define CAT_(A,B) A##B #define CAT(A,B) CAT_(A,B) #define CALLING_CONVENTION_SUPPORT( CONVENTION ) \ template<class R, class... Args> \ struct function_properties< R(CAT(__, CONVENTION) *)(Args...) >: \ signature_properties<R(Args...)> \ { \ using type = R(CAT(__, CONVENTION) *)(Args...) \ static const calling_convention convention = calling_convention::CONVENTION; \ static type from_pvoid(void const* pvoid) { \ return static_cast<type>(pvoid); \ } \ } CALLING_CONVENTION_SUPPORT(cdecl); CALLING_CONVENTION_SUPPORT(clrcall); CALLING_CONVENTION_SUPPORT(stdcall); CALLING_CONVENTION_SUPPORT(fastcall); CALLING_CONVENTION_SUPPORT(thiscall); CALLING_CONVENTION_SUPPORT(vectorcall); #undef CAT #undef CAT_ #undef CALLING_CONVENTION_SUPPORT
Icky Macros. And a serious bust. And unverified. But you have an idea.
Next, an assistant to do the work:
template<class FuncPtrType, class R, class Args> struct helper; template<class FuncPtrType, class R, class... Args> struct helper<FuncPtrType, R, types<Args...>> { FuncPtrType ptr; R operator()(Args...args)const { return ptr(std::forward<Args>(args)...); } helper(FuncPtrType p):ptr(p) {}; helper( helper const& )=default; helper& operator=( helper const& )=default; };
Perfect forwarding in an assistant would also be seductive.
Finally, we use the feature class above to bounce work from Entry to helper :
template<class FuncPtrType> struct Entry:helper< FuncPtrType, typename signature_properties<FuncPtrType>::return_type, typename signature_properties<FuncPtrTpye>::arguments > { using parent = helper< FuncPtrType, typename signature_properties<FuncPtrType>::return_type, typename signature_properties<FuncPtrTpye>::arguments >; Entry(void const* pvoid):parent( static_cast<FuncPtrType>(pvoid) ) {} };
except that we include the constructor in Entry to take void const* and forward the typed pointer to helper .
One change is that we drop from void* to our type of function at the earliest point we know is the type of function, and not at the point that we call.