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
- 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)
- 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.