Home > database >  function to retrieve member function pointer with n arguments
function to retrieve member function pointer with n arguments

Time:09-20

I need to implement a function to retrieve the function pointer of overloaded member functions with n arguments. So e.g. for the following class:

struct Test
{
    int func(int i1);
    int func(int i1, int i2);
    int func(int i1, int i2, int i3);
};

I need to retrieve one specific overload of Test::func. I already have the following implementation:

template<int Num> struct Overload {};


template<> struct Overload<0>
{
    template<class Ret, class Class>
    static auto from(Ret (*func)()) { return func; }

    template<class Ret, class Class>
    static auto from(Ret (Class::*meth)()) { return meth; }

    template<class Ret, class Class>
    static auto from(Ret (Class::*meth)() const) { return meth; }
};

template<> struct Overload<2>
{
    template<class Ret, class Class, class Arg1, class Arg2>
    static auto from(Ret (*func)(Arg1, Arg2)) { return func; }

    template<class Ret, class Class, class Arg1, class Arg2>
    static auto from(Ret (Class::*meth)(Arg1, Arg2)) { return meth; }

    template<class Ret, class Class, class Arg1, class Arg2>
    static auto from(Ret (Class::*meth)(Arg1, Arg2) const) { return meth; }
};

This implementation works as expected, but needs to be implemented separately for each argument count. From my understanding this would require https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4072.html which was rejected, but I could be missing something. Is there a way to derive the arguments from the template argument Num in C 17/C 20?

Edit: Some clarifications regarding comments / answers

  1. why not just use the arguments as template arguments: I already have a function for this purpose:
template<class... Args> struct OverloadArgs
{
    template<class Ret>
    static auto from(Ret (*func)(Args...)) {return func;}
    ...
};

E.g. for swizzling I simply have multiple overloads with different arg counts and it is a lot more concise to specify Overload<4>::from(&Test::swizzle) instead of OverloadArgs<int, int, int, int>::from(&Test::swizzle)

  1. This is used to wrap functions/classes to Python. As described in 1) it can be more concise to overload on arg count instead of arg type in some cases, which is why I would like to have both.

CodePudding user response:

Instead of specifying number of arguments, you can specify argument types

template<class... Args> struct Overload
{
    template<class Ret, class Class>
    static auto from(Ret(Class::* meth)(Args...)) { return meth; }
};

int main()
{
     Test t;  
     auto p2 = Overload<int, int>::from(&Test::func);  
     auto p0 = Overload<>::from(&Test::func);
     (t.*p0)();
     (t.*p2)(1,2);

    return 0;
}

UPD

Well... My knowledges are only enough for the following proposal

#define Overload_0 Overload<>
#define Overload_1 Overload<int>
#define Overload_2 Overload<int,int>

int main()
{
     Test t;  
     auto p2 = Overload_2::from(&Test::func);
     auto p0 = Overload_0::from(&Test::func);
     (t.*p0)();
     (t.*p2)(1,2);
     
    return 0;
}

CodePudding user response:

I'm not sure I completly understand your goal, but I think parameter pack can solve this. Template parameter pack (in this case named Args) allows you to pass a variable number of parameters.

struct Test {
    int func(int i1);
    int func(int i1, int i2);
    int func(int i1, int i2, int i3);
};

template<class Ret, class Class, class... Args>
auto From(Ret(Class::*meth)(Args...)) {
    return meth;
}

int main() {
    Test t;
    auto f = From<int, Test, int, int, int>(&Test::func);
    int result = std::invoke(f, t, 10, 11, 12);
}

I'm curious how you intend to use this, but there's probably a different and better approach.

  • Related