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; }); 
3
  • @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?' Commented May 27, 2014 at 12:16
  • If you read the answer to the other question, you'll know the answer to the second part of your question. Commented May 27, 2014 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>( [](int l, int r)->bool{return r > l; }); I was looking for something like Jarod42 's answer ! Commented May 27, 2014 at 12:50

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

Comments

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; })); 

2 Comments

Noting, of course, that this won't work with C++14's generic lambdas
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 template<class T>lambda_args_t=typename function_traits<T>::args_tuple_type, which reduces the noise in to_function's Return clause.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.