6

Context

Basically I need to have a const void *const for a member function, because that has to be passed to a third party library (which means I cannot use bind, function, etc). Since that seems to be impossible, I wanted to do the next best thing and map a member function to a static forwarding method, which I can then get the pointer for (passing this as first argument).

Question

I have a lot of functions that I need to register, with different signatures, so I would like to have a nice solution that allows me to convert a signature of a member function into a static method signature (passing this as an argument of course) - which I can then cast to a const void* const. So basically I want to do something like this:

So basically:

struct Foo
{ 
    MyType Bar(int a);
};

template <typename Ret, typename This, Ret(This::*Func)()>
struct CallWrap0
{
    static Ret &&Call(This* thisPtr)
    {
        return thisPtr->(*Func)();
    }
};

int Main()
{
    const void * const memberFunction = &(CallWrap0<MyType, Foo, Foo::Bar>()::Call);
    // etc.
}

The problem with this solution is that - even though it works - it's not very nice, because I have to explicitly tell the compiler the types. I'm looking for a solution where the compiler can fill in all the plumbing automagically.

I've been attempting to work around this with a helper function, so far without luck:

template <class Ret, class T, class... Args>
const void* const FunctionPtr(Ret (T::*function)(Args... args))
{
    // not sure... function is not a template, so this would require a class instance
    // which is not possible due to the ext. library constraints.
}
atlaste
  • 30,418
  • 3
  • 57
  • 87

1 Answers1

4
#include <utility>

template <typename T, T t>
struct CallWrap;

template <typename Ret, typename This, typename... Args, Ret(This::*Func)(Args...)>
struct CallWrap<Ret(This::*)(Args...), Func>
{
    static Ret Call(This* thisPtr, Args... args)
    {
        return (thisPtr->*Func)(std::forward<Args>(args)...);
    }
};

int main()
{
    auto f = &CallWrap<decltype(&Foo::Bar), &Foo::Bar>::Call;
}

DEMO


For MSVC, which fails to compile the above solution, try the below code:

template <typename T>
struct CallWrap;

template <typename Ret, typename This, typename... Args>
struct CallWrap<Ret(This::*)(Args...)>
{
    template <Ret(This::*Func)(Args...)>
    struct Function
    {
        static Ret Call(This* thisPtr, Args... args)
        {
            return (thisPtr->*Func)(std::forward<Args>(args)...);
        }
    };
};

int main()
{
    auto f = &CallWrap<decltype(&Foo::Bar)>::Function<&Foo::Bar>::Call;
}

DEMO 2

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160