20

In C++11 you can instantiate std::function like this:

std::function<void(int)> f1;
std::function<int(std::string, std::string)> f2;
//and so on

But while there is plenty of info on variadic templates on the web, I fail to find any articles on how to write std::function-like template which would accept parenthesized arguments. Could anyone please explain the syntax and its limitations or at least point to an existing explanation?

AndyG
  • 39,700
  • 8
  • 109
  • 143
Smiles
  • 1,733
  • 2
  • 11
  • 13

2 Answers2

24

There's nothing special about it, it's an ordinary function type. When you declare a function like this:

int foo(char a, double b)

Then its type is int (char, double). One way of "unwrapping" the individual argument types and return type is to use partial template specialisation. Basically, std::function looks something like this:

template <class T>
struct function; // not defined

template <class R, class... A>
struct function<R (A...)>
{
  // definition here
};
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
6

Pretty much like any other template, since int(std::string, std::string) is just a type.

Here's a really naive example that compiles:

template <typename FType>
struct Functor
{
   Functor(FType* fptr) : fptr(fptr) {}

   template <typename ...Args>
   void call(Args... args)
   {
      fptr(args...);
   }

private:
   FType* fptr;
};

void foo(int x, char y, bool z) {}

int main()
{
   Functor<void(int, char, bool)> f(&foo);
   f.call(1, 'a', true);
   //f.call(); // error: too few arguments to function
}

In reality you'd have a specialisation on FType being ReturnType(ArgTypes...), though my naive example will already give you the validation you need if you try to invoke it in in compatible ways.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055