简体   繁体   中英

Variadic template parameter order problem

I have a templated function wrapper that I am attempting to update to C++11 syntax (variadic paremeters).

My issue is that I am caught in a "catch 22" where ' Args... ' must be the last template parameter, but at the same time, cannot be defined after the function pointer template parameter.

Any idea if this can actually be solved?

  template <typename... Args, void(*Function)(Args...)>
  class function
  {
  public:

    void operator ()(Args... args) const
    {
      (*Function)(std::forward<Args...>(args...));
    }
  };

A possible way is to use the template specialization

template <typename>
struct myFunc;

template <typename R, typename ... Args>
struct myFunc<R(*)(Args...)>
 {
   // ...
 };

but, this way, you intercept (as template parameter) the type of the function pointer, not the function pointer itself; so you have to pass the function pointer in some way (constructor?).

Also observe that, if you want to use perfect forwarding, you have to transform operator() in a template method receiving arguments as universal references ( && ).

Something as follows

   template <typename ... As>
   R operator() (As && ... args) const
    {
      return fun(std::forward<As>(args)...);
    }

where fun is a pointer of type R(*)(Args...) .

The following is a full compiling example

#include <iostream>
#include <utility>

int foo (int, long)
 { return 42; }

template <typename>
struct myFunc;

template <typename R, typename ... Args>
struct myFunc<R(*)(Args...)>
 {
   using  funPnt = R(*)(Args...);

   funPnt  fun = nullptr;

   myFunc (funPnt f0) : fun{f0}
    { }

   template <typename ... As>
   R operator() (As && ... args) const
    {
      return fun(std::forward<As>(args)...);
    }
 };

int main ()
 { 
   myFunc<decltype(&foo)>  mf0{&foo};

   std::cout << mf0(1, 2l) << std::endl;
 }

If you really want the pointer function as template parameter (but, this way, every function determine a different type; this can be a good or a bad thing according to your needs), you can write the myFunc struct receiving before a type (the same pointer type) and then a value of that type.

So

template <typename T, T>
struct myFunc;

template <typename R, typename ... Args, R(*Func)(Args...)>
struct myFunc<R(*)(Args...), Func>
 {
   template <typename ... As>
   R operator() (As && ... args) const
    {
      return Func(std::forward<As>(args)...);
    }
 };

that can be declared

 myFunc<decltype(&foo), foo>  mf0;

If you can use C++17, you can simplify using auto for type of template values; so you can avoid the type

template <auto>
struct myFunc;

template <typename R, typename ... Args, R(*Func)(Args...)>
struct myFunc<Func>
 {
   template <typename ... As>
   R operator() (As && ... args) const
    {
      return Func(std::forward<As>(args)...);
    }
 };

and you can create a myFunc object as follows

myFunc<&foo> mf0;

Addendum: if you can use C++17, you can define a deduction guide for the first example (pointer as member, not as template value parameter)

template <typename R, typename ... Args>
myFunc (R(*)(Args...))  -> myFunc<R(*)(Args...)>;

so, instead of

myFunc<decltype(&foo)>  mf0{&foo};

you can simply write

myFunc  mf0{&foo};

Off Topic: I hope that you know that you're reinventing the wheel. As suggested by NathanOliver, the standard provide std::function .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM