Is it possible to allow one std::function type accept lambdas with different signatures
c++, c++11, std-function
Solution
I understand why you are using `std::function`: You have to know the return type of the transformation to create the vector, right?
But consider a completely different approach. Given the metafunction `std::result_of` you could compute the result type of a function call, so just write:
template<typename F , typename CONTAINER , typename T = typename std::result_of<F(typename CONTAINER::value_type)>::type>
std::vector<T> map( F f , CONTAINER&& container )
{
std::vector<T> result;
for( auto& e : container )
result.emplace_back( f( e ) );
return result;
}
Advantages:
No abuse of `std::function`: Always think what `std::function` does (i.e. type erasure), don't use it as an universal function type.
Rely on duck typing instead of coupling on the types: Don't worry, if something was wrong it wouldn't compile neither.
Works for any Standard Library Container since we extracted the element type with the `value_type` trait, instead of using `std::vector` directly.
The code is much more clear and efficient, both because the reduction of `std::function` usage.
Regarding the question "Its possible to write a function that accepts lambdas of multiple signatures?"
Using `std::function` you could write something similar to Boost.OverloadedFunction in a couple of lines:
template<typename F , typename... Fs>
struct overloaded_function : public std_function<F> , public std_function<Fs>...
{
overloaded_function( F&& f , Fs&&... fs ) :
std_function<F>{ f },
std_function<Fs>{ fs }...
{}
};
Where `std_function` is a metafunction which given a function type `F` returns the `std::function` instance with the signature of `F`. I leave it as a game/challenge for the reader.
Thats all. Improve it with a make-like function:
template<typename F , typename... Fs>
overloaded_function<F,Fs...> make_overloaded_function( F&& f , Fs&&... fs )
{
return { std::forward<F>( f ) , std::forward<Fs>( fs )... };
}
And you are ready to go:
auto f = make_overloaded_function( [](){ return 1; } ,
[](int,int){ return 2; } ,
[](const char*){ return 3; } );
f(); //Returns 1
f(1,2); //Returns 2
f("hello"); //Returns 3
EDIT: "Thanks. But, what I am really looking for, is a meta-function that takes the signature of a callable, and removes the const refs from the signature."
Ok, let me try: The `std::decay` metafunction applies the decaying done when passing argumments by value to a given type. This includes removing cv qualifiers, removing references, etc. So a metafunction like yours could be something that takes a function signature type and applies decaying to all its argumments:
template<typename F>
struct function_decay;
template<typename R typename... ARGS>
struct function_decay<R(ARGS...)>
{
using type = R(typename std::decay<ARGS>::type...);
};
That should do the work.
I have written this because you explicitly asked for it in the comment, but I strongly encourage you to use the alternative I showed you initially, because it has many advantages compared to your way. That said, I hope this answer helped to solve your problem.
Problem
I have a higher order function `map` which is similar to STL `for_each`, and maps a `std::function` object over a `vector` of things. ``` template<class T, class U> vector<U> map(function<U (T)> f, vector<T> xs) { vector<U> ret; for (auto &x: xs) ret.push_back(f(x)); return ret; } ``` Now, I want to have this higher order function take both objects of types `function<int (const vector<T>&)>` and `function<int (vector<T>)>`, as shown in the attached minimal example. The problem is that `function<int (const vector<T>&)>` and `function<int (vector<T>)>` seem to be convertible to each other (see `head` and `head2`), but `map` won't take the const references version `function<int (const vector<int>&)>` (see `Q1`). It is possible to tell `map` to accept the const reference version with explicit conversion (`Q2`), but this is rather cumbersome. I was wondering if, in general, it is possible to write a function `deref` that removes the const reference from `function<int (const vector<T>&)>` and returns a `function<int (vector<T>)>`? (If above is possible, then I won't have to write two identical overloads/implementations of map for const refs). Thanks. ``` #include <vector> #include <functional> using namespace std; template<class T, class U> vector<U> map(function<U (T)> f, vector<T> xs) { vector<U> ret; for (auto &x: xs) ret.push_back(f(x)); return ret; } int main() { vector<vector<int>> m; function<int (const vector<int>&)> head = [](const vector<int>& a) {return a[0];}; function<int (const vector<int>&)> head1 = [](vector<int> a) {return a[0];}; //conversion OK function<int (vector<int>)> head2 = [](const vector<int>& a) {return a[0];}; //conversion OK map(head2,m); //OK map(head,m); //Q1: problem line, implicit conversion NOT OK map(function<int (vector<int>)>(head),m); //Q2: explicit conversion OK map(deref(head),m); //Q3: ??How-to, deref takes a std::function f and returns a function with const ref removed from its signature return 0; } ``` --- EDIT --- I am particularly interested in a `deref` like function or a meta-function that can remove the const ref from the type signature of a `std::function` object, so that I can at least do `Q2` automatically. I know that, as @Brian and @Manu correctly pointed out, the use of `std::function` to specify types is not conventional, but I wonder what I asked above is even feasible. Personally, I think code with `std::function` has greater clarity, considering how generic function types `Func<T1, T2, T3, ...,Tn, Tresult>` are used in C#. This is if the cost of type erasure is tolerable. I fully agree that c++ can infer return types and give an error message when type is wrong. Maybe it's just a matter of taste and I would prefer to spell it out when writing function signatures.