How to convert lambda to std :: function using templates

Basically, what I want to do is take a lambda with any number of parameters of any type and convert it to std :: function. I tried the following and none of the methods work.

std::function([](){});//Complains that std::function is missing template parameters template <typename T> void foo(function<T> f){} foo([](){});//Complains that it cannot find a matching candidate 

The following code really works, but this is not what I want, because it requires explicitly specifying template parameters that do not work for general code.

 std::function<void()>([](){}); 

I've been hanging around with features and templates all day, and I just can't figure it out, so any help would be greatly appreciated.

As mentioned in the comment, the reason I am trying to do this is because I am trying to implement currying in C ++ using variable templates. Unfortunately this fails with lambda. For example, I can pass a standard function using a function pointer.

 template <typename R, typename...A> void foo(R (*f)(A...)) {} void bar() {} int main() { foo(bar); } 

However, I cannot figure out how to pass lambda to such a variational function. Why am I interested in converting a common lambda to a std :: function, because I can do the following, but ultimately it requires me to explicitly specify the template parameters in std :: function, which I am trying to avoid.

 template <typename R, typename...A> void foo(std::function<R(A...)>) {} int main() { foo(std::function<void()>([](){})); } 
+62
c ++ function lambda c ++ 11 templates
Nov 13 '12 at 9:59
source share
8 answers

You cannot pass an object to a lambda function as an argument of type std::function<T> without explicitly specifying a template argument T The calculation of the type of the template tries to match the type of your lambda function with std::function<T> , which it simply cannot do in this case - these types do not match. Calculation of the template type does not take into account conversions between types.

Perhaps if you can give it a different type inference method. You can do this by wrapping the function argument in an identity type so that it does not fail when trying to map the lambda to std::function (since dependent types are simply ignored by the type inference method) and some other arguments are given.

 template <typename T> struct identity { typedef T type; }; template <typename... T> void func(typename identity<std::function<void(T...)>>::type f, T... values) { f(values...); } int main() { func([](int x, int y, int z) { std::cout << (x*y*z) << std::endl; }, 3, 6, 8); return 0; } 

This is clearly not useful in your situation because you do not want to pass values ​​until a later time.

Since you do not want to specify template parameters and do not want to pass other arguments from which template parameters can be derived, the compiler will not be able to deduce the type of your argument std::function .

+44
Nov 13
source share

You can use dedicated / retrospective listing . If you have such a tool,

 #include <functional> using namespace std; template<typename T> struct memfun_type { using type = void; }; template<typename Ret, typename Class, typename... Args> struct memfun_type<Ret(Class::*)(Args...) const> { using type = std::function<Ret(Args...)>; }; template<typename F> typename memfun_type<decltype(&F::operator())>::type FFL(F const &func) { // Function from lambda ! return func; } 

you can tell FFL() all lambda types so that they are converted to what would be the correct version of std::function

 template <typename... Args> void Callback(std::function<void(Args...)> f){ // store f and call later } int main() { Callback(FFL([](int a, float b){ // do something })); return 0; } 

Display

+23
Jun 05 '14 at 19:13
source share

As shown in Deriving a call signature from a lambda or an arbitrary call to "make_function" , you can draw the calling signature of a lambda (or any other functor with one call signature) from your (one) operator() :

 template<typename T> struct remove_class { }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...)> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) const> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) volatile> { using type = R(A...); }; template<typename C, typename R, typename... A> struct remove_class<R(C::*)(A...) const volatile> { using type = R(A...); }; template<typename T> struct get_signature_impl { using type = typename remove_class< decltype(&std::remove_reference<T>::type::operator())>::type; }; template<typename R, typename... A> struct get_signature_impl<R(A...)> { using type = R(A...); }; template<typename R, typename... A> struct get_signature_impl<R(&)(A...)> { using type = R(A...); }; template<typename R, typename... A> struct get_signature_impl<R(*)(A...)> { using type = R(A...); }; template<typename T> using get_signature = typename get_signature_impl<T>::type; 

This is a pretty inflexible approach; as R. Martigno Fernandez says, it will not work for functors with several operator() s, as well as functors with the operator() pattern or for (C ++ 14) polymorphic lambdas. This is why bind rejects the output of its result type before a possible call attempt.

+14
Nov 13 '12 at 10:57
source share

You can get the necessary type std :: function for lambda using derivation, decltype, variadic templates and several types of attributes:

 namespace ambient { template <typename Function> struct function_traits : public function_traits<decltype(&Function::operator())> {}; template <typename ClassType, typename ReturnType, typename... Args> struct function_traits<ReturnType(ClassType::*)(Args...) const> { typedef ReturnType (*pointer)(Args...); typedef const std::function<ReturnType(Args...)> function; }; template <typename Function> typename function_traits<Function>::function to_function (Function& lambda) { return static_cast<typename function_traits<Function>::function>(lambda); } template <class L> struct overload_lambda : L { overload_lambda(L l) : L(l) {} template <typename... T> void operator()(T&& ... values){ // here you can access the target std::function with to_function(*(L*)this)(std::forward<T>(values)...); } }; template <class L> overload_lambda<L> lambda(L l){ return overload_lambda<L>(l); } } 

I use it in my code as follows:

ambient::lambda([&](const vector<int>& val){ // some code here // })(a);

PS: in my real case, I save this std :: function object and its arguments inside common kernel objects, which I can execute later on demand using virtual functions.

+7
Jan 21 '14 at 19:08
source share

Isn't currying already done with std::bind ?

 auto sum = [](int a, int b){ return a+b; }; auto inc = std::bind( sum, _1, 1 ); assert( inc(1)==2 ); 
+3
Nov 13 '12 at 10:28
source share

This may be interesting for you: https://gist.github.com/Manu343726/94769034179e2c846acc

This is an experiment that I wrote a month ago. The goal was to create a functor-like C ++ template that emulates closing private Haskell calls, i.e. Automatically closing mn arguments when you call with n , argument the function with m parameters.

This is one example of what this experiment can do:

 int f( int a, int b, int c, int d) { return a+b+c+d; } int main() { auto foo = haskell::make_function( f ); auto a = foo , 1 , 2 , 3; //a is a closure function object with one parameter std::cout << a , 4 << std::endl; //Prints 10 } 

haskell::make_function uses some type traits to take care of various types of function objects, including lambdas:

 auto f = haskell::make_function( []( int x, int y , int z ){ return x*y*z; } ); auto a = f(1,2); //a is functor with one parameter (Using the alternative C++-like syntax) auto b = a(3); // b is 6 

As you can see, I use the comma operator for the mmimic Haskell syntax, but you can change it to a call statement to achieve the syntax of the target.

You can freely do whatever you want with the code (Check license).

+3
Jun 05 '14 at 19:42
source share

C ++ 17 has constructor type deduction. This way you can save some typing for the std :: function template arguments. This is not quite anything, but a little less.

 template <typename R, typename...A> void foo(std::function<R(A...)>) {} int main() { foo(std::function([](){})); } 
+1
Feb 05 '19 at 7:20
source share

Seven years later, and perhaps the simplest solution, is still working today.

 template< char const * (*name) () > struct user { auto id() { return name(); } } ; 

Usage

Usage
 constexpr auto lama () { return "Lama"; } int main( int , char * [] ) { auto amuser = user< lama >{} ; cout << boolalpha << amuser.id() << endl ; } 

Amateur lambda also served

  auto cat = [] () constexpr { return "Cat"; } ; auto sneaky = user< cat >{} ; cout << boolalpha << sneaky.id() << endl ; 
0
Sep 20 '19 at 10:57
source share



All Articles