How to make C++11 functions taking function<> parameters accept lambdas automatically
Why would you want to create a dynamic indirection via std::function<...>
in the first place? Just templatize on the function object and you are sorted:
template <typename A, typename F>
auto map(F f, std::vector<A> arr) -> std::vector<decltype(f(arr[0]))> {
std::vector<decltype(f(arr[0]))> res;
for (int i=0; i<arr.size(); ++i)
res.push_back(f(arr[i]));
return res;
}
In fact, there isn't really any need for nailing the container type either and you probably want to pass it by [const
] reference as well:
template <typename C, typename F>
auto map(F f, C const& c) -> std::vector<decltype(f(*c.begin()))> {
std::vector<decltype(f(*c.begin()))> res;
for (auto const& value: c)
res.push_back(f(value));
return res;
}
Finally, please note that the standard C++ library already as a "map" function. It just happens to be spelled std::transform()
and has an interface which fits the generic approach in C++ better:
std::vector<int> result;
std::transform(a.begin(), a.end(), std::back_inserter(result),
[](int x){ return x;});
Your map function is broken. Do not use std::function
unless you cannot use a template; and in this instance, you most assuredly can. You don't need B
as a template parameter because decltype
can give it to you, and you don't need the argument type to actually be a std::function
at all.
template <typename A, typename F> auto map(F f, vector<A> arr) -> std::vector<decltype(f(arr.front())> {
std::vector<decltype(f(arr.front())> res;
for (int i=0;i<arr.size();i++) res.push_back(f(arr[i]));
return res;
}
For the record, this is ignoring everything else wrong with your map function.
Finally figured out a generic wrapper function make_function
(in current c++11) for converting any lambda to its corresponding std::function
object with type deduction. Now instead of using ctor:
map(function<int (int)>( [](int x) -> int { return x;} ), {1,2,3});
which requires giving the same type information twice, the following succinct form works
map(make_function([](int x) -> int { return x;}),a); //now OK
Code is below:
#include <vector>
#include <functional>
using namespace std;
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
typedef function<ReturnType (Args...)> f_type;
};
template <typename L>
typename function_traits<L>::f_type make_function(L l){
return (typename function_traits<L>::f_type)(l);
}
template <typename A,typename B>
vector<B> map(std::function<B (A)> f, vector<A> arr) {
vector<B> res;
for (int i=0;i<arr.size();i++) res.push_back(f(arr[i]));
return res;
}
int main () {
vector<int> a = {1,2,3};
map(make_function([](int x) -> int { return x;}),a); //now OK
return 0;
}
--original answer--
To answer my own question after a couple of weeks' search (and getting chastised for using std::function<> as parameters), probably the best way I can find to have function<>-typed parameters accept lambda's (in c++11) is simply via explicit cast:
map((function<int (int)>) ([](int x) -> int { return x;} ), {1,2,3});
Or using ctor:
map(function<int (int)>( [](int x) -> int { return x;} ), {1,2,3});
For comparison, if you have a function taking std::string (e.g. void ff(string s) {...}
), it can take const char*
automatically. (ff("Hi")
would work). The automatic conversion from lambda to std::function<>
does not similarly work in c++11 (, which is unfortunate, IMO).
Hopefully, things will improve in c++14/1y when lambdas can be properly typed or better type-deduced.