Is it possible to extract parameter types from the <auto MEMFN> template?
Is it possible to create an autonomous template function that has the auto MEMFN template parameter (member function pointer) and has the same return types and parameters as MEMFN?
So, if the type is MEMFN
RETURN (OBJECT::*)(PARAMETERS...) then the desired function is as follows:
template <auto MEMFN> RETURN foo(OBJECT &, PARAMETERS...); My problem is how to extract PARAMETERS... from the MEMFN type ( RETURN and OBJECT easy to do).
Therefore, I can call this function as follows:
Object o; foo<&Object::func>(o, <parameters>...); As for the request from nm, here is an example from the actual code:
#include <utility> template <typename RETURN, typename OBJECT, typename ...PARAMETERS> struct Wrapper { template <RETURN (OBJECT::*MEMFN)(PARAMETERS...)> RETURN foo(PARAMETERS... parameters) { // do whatever with MEMFN, parameters, etc. here, not part of the problem } }; struct Object { template <auto MEMFN, typename RETURN, typename OBJECT, typename ...PARAMETERS> RETURN call(OBJECT &&object, PARAMETERS &&...parameters) { // here, MEMFN parameters and PARAMETERS must be the same // Wrapper actually not created here, it is accessed by other means Wrapper<RETURN, typename std::decay<OBJECT>::type, PARAMETERS...> w; return w.template foo<MEMFN>(std::forward<PARAMETERS>(parameters)...); } }; struct Foo { void fn(int); }; int main() { Object o; Foo f; o.call<&Foo::fn, void, Foo &, int>(f, 42); // this is wanted instead: // o.call<&Foo::fn>(f, 42); } If you relax your demand for autonomy, you can do something like:
#include <iostream> template <auto MEMFN, class = decltype(MEMFN)> struct S; template <auto MEMFN, class Ret, class T, class... Args> struct S<MEMFN, Ret (T::*)(Args...)> { static Ret foo(T &o, Args... args) { (o.*MEMFN)(args...); } }; struct A { void foo(int a, int b) { std::cout << a << " " << b << std::endl; } }; int main() { A a; S<&A::foo>::foo(a, 1, 2); } If not, then you will need to be patient to create an overload function for every possible number of parameters:
#include <type_traits> #include <tuple> #include <iostream> template <class, std::size_t> struct DeduceParam; template <class Ret, class T, class... Args, std::size_t N> struct DeduceParam<Ret (T::*)(Args...), N> { using type = std::tuple_element_t<N, std::tuple<Args...>>; }; template <class> struct DeduceResultAndType; template <class Ret, class T, class... Args> struct DeduceResultAndType<Ret (T::*)(Args...)> { using result = Ret; using type = T; static constexpr decltype(sizeof(T)) size = sizeof...(Args); }; template <auto MEMFN, class DRAT = DeduceResultAndType<decltype(MEMFN)>, std::enable_if_t<DRAT::size == 1>* = nullptr> typename DRAT::result foo(typename DRAT::type o, typename DeduceParam<decltype(MEMFN), 0>::type param1) { } template <auto MEMFN, class DRAT = DeduceResultAndType<decltype(MEMFN)>, std::enable_if_t<DRAT::size == 2>* = nullptr> typename DRAT::result foo(typename DRAT::type o, typename DeduceParam<decltype(MEMFN), 0>::type param1, typename DeduceParam<decltype(MEMFN), 1>::type param2) { } struct A { void foo(int a, int b) { std::cout << a << " " << b << std::endl; } }; int main() { A a; foo<&A::foo>(a, 1, 2); } Yes we can:
template <auto MemFn> struct fooHelper; template <typename Ret, typename Obj, typename ... Args, Ret (Obj::*MemFn)(Args...)> struct fooHelper<MemFn> { static Ret call(Obj& obj, Args... args) { return (obj.*MemFn)(args...); } }; template <auto MemFn, typename ... Args> auto foo(Args ... args) { return fooHelper<MemFn>::call(args...); } Another way to define foo that does not introduce a new parameter package:
template <auto MemFn> auto& foo = fooHelper<MemFn>::call; Usage example:
#include <iostream> struct moo { int doit (int x, int y) { return x + y; } }; int main() { moo m; std::cout << foo<&moo::doit>(m, 1, 2) << "\n"; } (Perfect shipment omitted for simplicity)