Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template parameter - function pointer with variadic arguments

I know I can do this:

template<typename T, typename Ret, typename A1, typename A2, Ret(T::*F)(A1, A2)>
class C{}

But as you can see this A1 and A2 are bit ugly. In fact I don't know the number of arguments. Sounds like a work for variadic templates. Unfortunately I can't do this:

// doesn't work - parameter pack must appear at the end of the template parameter list
template<typename T, typename Ret, typename... Args, Ret(T::*F)(Args...)>
class C{}

Nor this:

template class C;

// doesn't work - wrong syntax
template<typename T, typename F, typename Ret, typename... Args>
class Delegate2<Ret(T::*F)(Args...)>{}

Do I want too much?

like image 786
nikitablack Avatar asked Apr 11 '16 12:04

nikitablack


People also ask

What is Variadic template in C++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.

Is printf Variadic function?

Variadic functions are functions (e.g. printf) which take a variable number of arguments.

Why use function pointers?

Function pointers can be useful when you want to create callback mechanism, and need to pass address of a function to another function. They can also be useful when you want to store an array of functions, to call dynamically for example.


2 Answers

You could do the following:

template<typename T, T> struct C;

template<typename T, typename R, typename ...Args, R (T::*F)(Args...)>
struct C<R (T::*)(Args...), F> {

  R operator()(T &obj, Args &&... args) {
    return (obj.*F)(std::forward<Args>(args)...);
  }

};

and then in your program:

struct A {
  int foo(int i) { return i; }
};

int main() {
  C<int(A::*)(int), &A::foo> c;
  A a;
  std::cout << c(a, 42) << std::endl;
}

Live Demo

like image 107
101010 Avatar answered Nov 13 '22 19:11

101010


template<class T>struct tag{using type=T;};
template<class Tag>using type=typename Tag::type;

template<class T, class Sig>
struct member_function_pointer;
template<class T, class Sig>
using member_function_pointer_t=type<member_function_pointer<T,Sig>>;

template<class T, class R, class...Args>
struct member_function_pointer<T, R(Args...)>:
  tag<R(T::*)(Args...)>
{};

then

template<class T, class Sig, member_function_pointer_t<T,Sig> mf>
class C{};

should do the trick. If you need access to Args..., you can specialize.

template<class T, class Sig, member_function_pointer_t<T,Sig> mf>
class C;
template<class T, class R, class...Args, member_function_pointer_t<T,R(Args...)> mf>
class C<T, R(Args...), mf> {
};

like that.

like image 38
Yakk - Adam Nevraumont Avatar answered Nov 13 '22 19:11

Yakk - Adam Nevraumont