Reputation: 2998
This might look similar to "I cannot pass lambda as std::function", but I'm actually passing the std::function
parameter by value, so that problem doesn't apply. I've defined the following function.
template<typename T>
std::vector<T> countSort(const std::vector<T> &v, std::function<int(T)> keyFunc, int n);
The second parameter is an std::function
that maps T
to int
(passed by value).
When calling this, I wanted to use a lambda expression, as follows:
std::vector<int> v;
[...]
v = countSort(v, [](int x) { return x; }, 10);
But the template argument deduction fails, because "main()::<lambda(int)>
is not derived from std::function<int(T)>
". It does work if I specify the template argument, or if I introduce an intermediate variable of type std::function
for the lambda expression:
std::function<int(int)> lambda = [](int x) { return x; };
v = countSort(v, lambda, 10);
Why can't I do the former? I'm giving the compiler the exact same information; if it is able to convert a value of type lambda<int>
to std::function<int(int)>
when assigning it to a variable, why can't it directly convert from lambda<int>
to the parameter type, which is std::function<T(int)>
—and taking into account that v
is of type std::vector<int>
, it should know that T
is int
? The whole reason I want to use a lambda expression is precisely that, it's an expression, so I should be able to write it inline in the function call argument list, without having to give it a name or assign it to a variable.
Upvotes: 1
Views: 1298
Reputation: 172884
The problem is, template argument deduction doesn't consider implicit conversion (from lambda to std::function
), which causes the deduction for T
on the 2nd function parameter keyFunc
to fail.
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
You can use std::type_identity
(since C++20) to exclude the 2nd function parameter from deduction. e.g.
template<typename T>
std::vector<T> countSort(const std::vector<T> &v, std::function<int(std::type_identity_t<T>)> keyFunc, int n);
BTW: If your compiler doesn't support std::type_identity
, it's not hard to make one.
And about how std::type_identity
works here, see non-deduced context:
(emphasis mine)
In the following cases, the types, templates, and non-type values that are used to compose
P
do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
- The nested-name-specifier (everything to the left of the scope resolution operator
::
) of a type that was specified using a qualified-id:
Upvotes: 7