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::functionFrom 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