I have a list of numbers.
I am trying to filter the list and only keep the positive numbers.
I am trying to do it by passing a lambda as an argument.
I wonder why I get function mismatch error.
#include <vector>
#include <algorithm>
#include <functional>
template<typename T>
std::vector<T> keep(
const std::vector<T> &original,
std::function<bool(const T&)> useful)
{
std::vector<T> out;
for(T item:original)
{
if(useful(item))
out.push_back(item);
}
return out;
}
int main()
{
std::vector<int> a={4,6,2,-5,3,-8,13,-11,27};
a=keep(a,[](const int& x)->bool{return x>0;});
for(int y:a)
{
std::cout<<y<<std::endl;
}
return 0;
}
And this is the error message:
error: no matching function for call to ‘keep(std::vector<int>&, main()::<lambda(const int&)>)’
a=keep(a,[](const int& x)->bool{return x>0;});
^
Change the function keep
to
template<typename T, typename Func>
std::vector<T> keep(const std::vector<T> &original,
Func useful)
{
// code as usual
}
Live example.
This works with an argument to useful
being any one of these:
std::function
From the documentation:
The lambda expression constructs an unnamed prvalue temporary object of unique unnamed non-union non-aggregate type, known as closure type.
This means that two lambdas with the same code, would generate two different typed objects.
auto f1 = [](int) { return true; };
auto f2 = [](int) { return false; };
f2 = f1; // error: no viable '='
However, both of these are implicitly convert-able to the corresponding std::function
types:
std::function<bool(int)> fn = f1;
fn = f2;
But then why doesn't it work in your case? This is because of template type deduction. Changing keep
to
template<typename T>
std::vector<T> keep(const std::vector<T> &original,
std::function<bool(const int &)> useful)
// no type deduction for std::function's template, explicitly mentioned
will make your example compile without any cast at the caller site.
However, trying to match it against std::function<T>
won't work since template type deduction doesn't consider any conversion. Template argument deduction looks for exact type matches. Implicit conversions don't matter at this stage. You've to explicitly cast it to a matching std::function
as Atomic_alarm comments. Like Joseph says in How to convert a lambda to an std::function using templates:
Template type deduction tries to match the type of your lambda function to the
std::function<T>
which it just can't do in this case - these types are not the same. Template type deduction doesn't consider conversions between types.
While in the alternative solution what happens is something like this:
auto f = [](int i) { return (i >= 0); }
The type of f
here is not std::function
but some unnamed type deduced like it would for the template parameter Func
above.
If you still want to do it the std::function
way, see this answer which does it with an additional template indirection. See this answer and this post for related details.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With