Luca
Luca

Reputation: 1756

std::function type and template instantiation

I'm new to C++ and I'm learning about lambdas,functors and callables, and I know that there's a wrapper class, namely std::function that allows callables of different types to be stored and called (as long as the have the same call signature,or function type).

Now, I understand that you can have function with function type parameters that are really just function pointer parameters as in :

void fun(int,int*(int,int&));

which is nothing more than a function that takes an int and a function pointer to a function like int *f(int,int&),even if the language allows me to pass a function as an argument (with or without the ampersand).Infact, the function parameter list might as well be written as:

void fun(int,int*(*)(int,int&));

Now,back to the std::function type

I know that I can instantiate std::function with a function type and that allows any kind of callable to be passed to the wrapper. But, a function type is not a type I can use as a template type argument in any instantiation such as:

std::vector<int(int)> f_vec;

instead, I should make a vector of function pointers

std::vector<int(*)(int)> f_vec;

and that would allow me to insert pointers to function,but not functors or lambdas.

So, my question is, how can I instantiate a template with a type argument like a function type?? what's happening under the hood in the library std::function type.I mean a function type seems to me a type I cannot use in templates?? pleas can you make things a little clearer,as I'm just beginning to learn these topics. Thanks

Upvotes: 3

Views: 451

Answers (1)

The reason why you cannot write std::vector<int(int)> is not something fundamental about using function types as template parameters. That's perfectly valid. It's just what std::vector<T> does with the T (like operate on it by value) which makes std::vector<int(int)> illegal.

This can be shown by using std::vector<int(int)> in a context where nothing bad happens, such as this:

typedef std::vector<int(int)> StillOk;
StillOk *p = nullptr;

As long as the template doesn't actually try to do anything illegal with int(int), it's fine.

So, as long as your template deals with its template parameter in a way which is legal for function types, you can use it with function types. Here's a hypothetical example:

template <class T>
struct MyPointer
{
  T *p;
  T& operator* () const { return *p; }
};

It's now perfectly legal to instantiate MyPointer<int(int)> and use its operator *, because it will only ever involve expressions of type int (*)(int) and int (&)(int). [Live example]

And that's pretty much also what std::function<T> does with its T—only things which are legal with a function type.

Upvotes: 8

Related Questions