简体   繁体   中英

Passing a lambda argument to a std::function parameter without intermediate variable

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.

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. eg

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.

  1. The nested-name-specifier (everything to the left of the scope resolution operator :: ) of a type that was specified using a qualified-id :

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