1

Why the following code does not compile?

template <class T>
void sort2( std::function<bool(T, T)> sort_func){
}

int main()
{
    sort2( [](int  l, int  r)->bool{return  r > l; });
}


    error C2784: 'void sort2(std::function<bool(T,T)>)' :
 could not deduce template argument for 'std::function<bool(T,T)>'

Is there any way to make that code compile without saying template parametrs explicitly?

sort2<int>( [](int  l, int  r)->bool{return  r > l; });
uchar
  • 2,552
  • 4
  • 29
  • 50
  • @ildjarn How is this question is duplicate of that one ?!! look at the second part of my question 'Is there any way to make that code compile without saying template parametrs explicitly?' – uchar May 27 '14 at 12:16
  • If you read the answer to the other question, you'll know the answer to the second part of your question. – ildjarn May 27 '14 at 12:26
  • @ildjarn that answer doesn't help me much... I read that question before asking this one !!If you look my question carefully you see that I know that stuffs: sort2( [](int l, int r)->bool{return r > l; }); I was looking for something like Jarod42 's answer ! – uchar May 27 '14 at 12:50

2 Answers2

4

A std::function is a type erasure class, which can type erase lambdas among other types.

It is otherwise unrelated to the type of a lambda.

There are only a few good reasons to deduce the type of a type erasure class (overloading mainly). What you probably want is a concept requires clause or the like, which is coming sometime after C++1y, and solves the problem better than deducing the type of a std::function.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1

A lambda is not a std::function, it needs a conversion. so compiler cannot found an exact match with the lambda.

You have to force the conversion of the lambda to a function or explicitly set template argument.

You may force the conversion to function with something like:

namespace detail
{

template <typename T> struct function_traits {};

template <typename C, typename Res, typename...Args>
struct function_traits<Res (C::*)(Args...)const>
{
    using result_type = Res;
    using args_tuple_type = std::tuple<Args...>;
};

template <typename C, typename T> struct to_function;

template <typename C, typename... Ts> struct to_function<C, std::tuple<Ts...>>
{
    using Ret = typename function_traits<decltype(&C::operator())>::result_type;

    std::function<Ret (Ts...)> operator() (C c) const { return c; }
};

}

#define Return(res) decltype res { return res; }

template <typename Lambda>
auto to_function(Lambda lambda)
    -> Return((detail::to_function<Lambda, typename detail::function_traits<decltype(&Lambda::operator())>::args_tuple_type>()(std::forward<Lambda>(lambda))))

And then use it like:

sort2(to_function([](int  l, int  r)->bool{return  r > l; }));
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 1
    Noting, of course, that this won't work with C++14's generic lambdas – ildjarn May 27 '14 at 12:56
  • 2
    First, note that there is rarely a good reason to deduce a `std::function`'s type: if you are deducing its type, you could instead just use the non-type erased object. Second, add a `templatelambda_args_t=typename function_traits::args_tuple_type`, which reduces the noise in `to_function`'s `Return` clause. – Yakk - Adam Nevraumont May 27 '14 at 13:08