Lambdas and std :: function

I am trying to catch up with C ++ 11 and all the great new features. I got a little stuck on lambdas.

Here is the code I managed to get:

#include <iostream> #include <cstdlib> #include <vector> #include <string> #include <functional> using namespace std; template<typename BaseT, typename Func> vector<BaseT> findMatches(vector<BaseT> search, Func func) { vector<BaseT> tmp; for(auto item : search) { if( func(item) ) { tmp.push_back(item); } } return tmp; } void Lambdas() { vector<int> testv = { 1, 2, 3, 4, 5, 6, 7 }; auto result = findMatches(testv, [] (const int &x) { return x % 2 == 0; }); for(auto i : result) { cout << i << endl; } } int main(int argc, char* argv[]) { Lambdas(); return EXIT_SUCCESS; } 

I would like to have the following:

 template<typename BaseT> vector<BaseT> findMatches(vector<BaseT> search, function <bool (const BaseT &)> func) { vector<BaseT> tmp; for(auto item : search) { if( func(item) ) { tmp.push_back(item); } } return tmp; } 

Basically, I want to narrow down possible lambdas to a reasonable subset of functions. What am I missing? Is it possible? I am using GCC / g ++ 4.6.

+4
c ++ lambda c ++ 11 templates
source share
2 answers

Stefan T. Loveaway explains why this does not work in this video . The main problem is that the compiler is trying to infer BaseT from the std::vector and std::function parameters. A lambda in C ++ is not a type of std::function , it is an unnamed, unique non-unit type that can be converted to a function pointer if it does not have a capture list (empty [] ). On the other hand, the std::function object can be created from any possible type of the called object (function pointers, function function pointers, function objects).

Note that I personally don’t understand why you want to restrict incoming functions to this particular signature (in addition to the fact that indirectness through the shell of polymorphic functions, such as std::function , is much more inefficient than directly calling a functor (which can even be built-in)), but here is the working version. Basically, it disables the argument output in the std::function and only outputs BaseT from the std::vector argument:

 template<class T> struct Identity{ typedef T type; }; template<typename BaseT> vector<BaseT> findMatches(vector<BaseT> search, typename Identity<function<bool (const BaseT &)>>::type func) { vector<BaseT> tmp; for(auto item : search) { if( func(item) ) { tmp.push_back(item); } } return tmp; } 

Live example on Ideone.

Another possible way would be to not restrict the type of functor directly, but indirectly via SFINAE:

 template<class T, class F> auto f(std::vector<T> v, F fun) -> decltype(bool(fun(v[0])), void()) { // ... } 

Live example on Ideone.

This function will be removed from the overload set if fun does not accept an argument of type T& or if the return type is not converted to bool . , void() returns f the return type of void .

+9
source share

As other posters have shown, this is the output of the template argument for std :: function.

One intuitive way to make the second code snippet is to add a base type when calling the template function: findMatches<int> .

Another way not mentioned by Xeo is to use std :: is_convertible:

 template<typename BaseT, typename FUNC> vector<BaseT> findMatches(vector<BaseT> search, function <bool (const BaseT &)> func) { static_assert(std::is_convertible<FUNC, function<bool (const BaseT &)> >::value, "func must be convertible to ..."); vector<BaseT> tmp; for(auto item : search) { if( func(item) ) { tmp.push_back(item); } } return tmp; } 

It avoids wrapping lamda in std :: function and provides an error message.

0
source share

All Articles