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:
- lambda
std::function
- functor
- function pointer
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.