Reputation: 1756
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
Reputation: 171117
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