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.

Original source