Reputation: 1287
If you have the following template for filtering list:
template <typename T>
inline std::list<T> list_filter(std::list<T> const& a, bool (f)(T)) {
std::list<T> output;
std::copy_if(a.begin(), a.end(), std::back_inserter(output), f);
return output;
}
Then try to call it with the lambda inside like:
std::list<int> lst = {1,2,3,4,5};
auto filtered = list_filter(lst, [](int el) -> bool { return (el % 2 == 0); });
It will produce the error with no matching function for call to list_filter(..., std::__cxx11::list<int>)::<lambda(int)>)'
.
Is there any way to bypass that restriction without extracting the lambda into the separate function? Why C++ doesn't allow this obvious pattern?
Upvotes: 2
Views: 225
Reputation: 172964
Implicit conversion (from lambda with no capture-list to function pointer) won't be considered in template argument deduction, which fails to deduce template argument T
on the 2nd function argument.
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 convert lambda to function pointer explicitly by static_cast
, or operator+
. e.g.
auto filtered = list_filter(lst, +[](int el) -> bool { return (el % 2 == 0); });
Or use std::type_identity
(since C++20) to exclude the 2nd function argument from deduction. e.g.
template <typename T>
inline std::list<T> list_filter(std::list<T> const& a, bool (f)(std::type_identity_t<T>)) {
...
}
BTW you can make your own type_identity
easily if your compiler doesn't support C++20.
Upvotes: 6
Reputation: 409364
Lambdas with captures are not compatible with pointers to functions (which is what the argument f
is).
I recommend that you take a hint from the standard library itself when it comes to callable objects: Use template arguments for the whole callable object:
template <typename T, typename F>
inline std::list<T> list_filter(std::list<T> const& a, F f) {
std::list<T> output;
std::copy_if(a.begin(), a.end(), std::back_inserter(output), f);
return output;
}
Upvotes: 4