Search code examples
c++templatesvariadic-templates

How to extract the arguments of a function pointer as type parameter pack?


I would like to support calls like this

class BaseClass {
public:
  virtual void print2(float arg1, float arg2) = 0;
};

int main() {
  invoke(subclass, &BaseClass::print2, 1, 2);      
}

where

  1. subclass is automatically upcasted to BaseClass
  2. the arguments are automatically converted from int to float
  3. calls with wrong parameter types / class types cause errors

I managed to solve the part with the base class. But the argument part gives me a headache. My approach is to extract all the needed type information from the handed function pointer. The other arguments are casted implicitly then (if possible).

What i have so far is this:

template<class Func> struct FunctionPointer2 {};

template<class Class, typename Arg1, typename Arg2> struct FunctionPointer2<void (Class::*)(Arg1, Arg2)> {
  typedef Class Class;
  typedef Arg1 Argument1;
  typedef Arg2 Argument2;
};

template <typename Func>
void invoke2(typename FunctionPointer2<Func>::Class* obj, Func func, typename FunctionPointer2<Func>::Argument1 arg1, typename FunctionPointer2<Func>::Argument2 arg2) {
  (obj->*func)(arg1, arg2);
}

It works but for each count of parameters another function, function pointer struct, ... is needed.

So here's the question: Is following even possible? How can i make it possible?

template<class Func> struct FunctionPointer {};

template<class Class, typename ... Args> struct FunctionPointer<void (Class::*)(Args ...)> {
  typedef Class Class;
  typedef Args Arguments; // pass type parameter pack here
};

template <typename Func>
void invoke(typename FunctionPointer<Func>::Class* obj, Func func, typename FunctionPointer<Func>::Arguments ... params) {
  (obj->*func)(params ...);
}

Thanks for you help :)


Solution

  • Both the manual upcast and extracting the parameter types should be unnecessary.

    You can just do this:

    template <typename T, typename M, typename ...P>
    void invoke(T &&object, M member, P &&... params)
    {
        (std::forward<T>(object).*member)(std::forward<P>(params)...);
    }