74

Basically, what I want to be able to do is take a lambda with any number of any type of parameters and convert it to an std::function. I've tried the following and neither method works.

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 does work however, but it is not what I want because it requires explicitly stating the template parameters which does not work for generic code.

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

I've been mucking around with functions and templates all evening and I just can't figure this out, so any help would be much appreciated.

As mentioned in a comment, the reason I'm trying to do this is because I'm trying to implement currying in C++ using variadic templates. Unfortunately, this fails horribly when using lambdas. 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 can't figure out how to pass a lambda to such a variadic function. Why I'm interested in converting a generic lambda into an std::function is because I can do the following, but it ends up requiring that I explicitly state the template parameters to std::function which is what I am trying to avoid.

template <typename R, typename...A>
void foo(std::function<R(A...)>) {}
int main() {
    foo(std::function<void()>([](){}));
}
retep998
  • 888
  • 1
  • 9
  • 14
  • 6
    Lambdas are not special. They're just function objects. And this is also a function object: `struct foo { void operator()(int); void operator()(std::string); };`. How would you idea work for this one? – R. Martinho Fernandes Nov 13 '12 at 10:02
  • What is it you want to achieve? Could you show some pseudo code? – ronag Nov 13 '12 at 10:02
  • I was actually trying to implement currying in C++, but then when I tried to deduce the parameters of a lambda using variadic templates, it all broke down. So I was hoping if I could simply convert the lambda to a std::function, my problems would be solved. – retep998 Nov 13 '12 at 10:06
  • Incidentally, are you familiar with `std::bind`? – Rook Nov 13 '12 at 10:15
  • Yes, and it does not play nice with variadic templates. For example, if I have a function `int foo(int x, int y){return x*y;}` and I do `std::bind(foo, 7)(5);`, gcc starts throwing errors at me. In order to make it work correctly I have to do `std::bind(foo, 7, _1)(5);`, but that requires explicitly stating the placeholders and thereby ruins the variadicness. – retep998 Nov 13 '12 at 10:19
  • @retep998: so you need a placeholder called `_LAST`? – xtofl Nov 13 '12 at 10:29
  • Then instead may I recommend Haskell? ;-) – Rook Nov 13 '12 at 10:37
  • @xtofl A placeholder like that would be nice. However implementing it would run into the same problems which I am having here. So either what I am trying to do is possible, or _LAST is impossible to have. – retep998 Nov 13 '12 at 10:38
  • 2
    I don't think this feature can be implemented in a generic way. Consider a structure with multiple `operator ()`s accepting different argument types. What kind of `std::function` should it fit into? – hpsMouse Nov 13 '12 at 10:45
  • Even ignoring the implementation detail that it has to be shoved into a `std::function`, currying a functor with different `operator()` overloads would presumably produce a functor also with multiple `operator()` overloads. For example if I have `int,int` and `int,float` to start with, I can bind the first parameter and be left with `int` and `float` overloads. Presumably that would have to be a single template `operator()` with some fairly impressive `enable_if`-ery. – Steve Jessop Nov 13 '12 at 11:00
  • @SteveJessop Being able to generically have all the overloads of a functor curried would in fact be fantastic, but I have absolutely no idea how to go about doing that. Another issue is if the functor provides two overloads `(int)` and `(int, int)`. If I have greedy currying, if I did `curriedfunctor(6)(7)`, the `(6)` would greedily evaluate the `(int)` overload, thus resulting in an error at `(7)`. It would be impossible to call the `(int, int)` overload. – retep998 Nov 13 '12 at 11:16
  • @retep998: good point. I wonder whether any functional languages allow the equivalent of that `operator()` overload. If not whether this is why, and if so what they do about it. I suppose that in the languages where all functions take exactly one argument, that's problem solved ;-) – Steve Jessop Nov 13 '12 at 11:23
  • @retep998 : I'm assuming you're already familiar with [Boost.Phoenix](http://www.boost.org/libs/phoenix/)? – ildjarn Nov 13 '12 at 18:03
  • `std::function` is not an appropriate tool for what you're intent on doing. [Here](https://bitbucket.org/mickk/annex/src/76466a45d84d015389ab9acc4e49978f2d8d5e78/include/annex/functional/curry.hpp?at=default)'s my take on a currying feature that works for overloaded functors. I tried to write an answer based on it, but my code relies on quite a few utilities of mine. [Here](http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer) is a very useful trick when using variadic tuples -- it is very handy for those kind of things. – Luc Danton Nov 14 '12 at 06:52

10 Answers10

54

You can't pass a lambda function object as an argument of type std::function<T> without explicitly specifying the template argument T. Template type deduction tries to match the type of your lambda function to the std::function<T> which it just can't do in this case - these types are not the same. Template type deduction doesn't consider conversions between types.

It is possible if you can give it some other way to deduce the type. You can do this by wrapping the function argument in an identity type so that it doesn't fail on trying to match the lambda to std::function (because dependent types are just ignored by type deduction) and giving some other arguments.

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 obviously not useful in your situation though because you don't want to pass the values until later.

Since you don't want to specify the template parameters, nor do you want to pass other arguments from which the template parameters can be deduced, the compiler won't be able to deduce the type of your std::function argument.

Pradhan
  • 16,391
  • 3
  • 44
  • 59
Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • Ah well. I might as well just constraint myself to simple function pointers, because apparently lambdas just won't work for my purposes. Though I do hope they provide some way to deal with lambdas in variadic templates in a future standard. – retep998 Nov 13 '12 at 10:54
  • crap. I thought that it will be unambiguous since lambdas have only one `op()`. – Bartek Banachewicz Apr 16 '13 at 16:07
29

TL;DR: What you ask can be done using CTAD, a feature that enables you to create an std::function of the expected type, right at the call site without spelling out the template arguments:

foo(std::function([](int arg){ return Bar{}; }));
//  ^^^^^^^^^^^^^ constructor call w/o templates
// std::function<Bar(int)>  will be auto-deduced

Demo

If you are interested on how to emulate the mechanics of such a deduction, or need to work with a pre c++17 compiler, check the rest of the answer.


You can use a dedicated/retrospective cast. Once you have a tool like this

#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 say FFL() to all lambda types to have them 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

Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
  • 2
    This FFL thing is beautiful! Changing the prototype of _`Callback`_ with: _`template `_ _`auto parameter_grinding_callback(std::function f) -> decltype(f)`_ one can then write: _`auto omg = parameter_grinding_callback(FFL([](int a){std::cout << a << std::endl;}));`_ _`omg(5);`_ – Avio May 12 '17 at 11:36
  • 1
    This is a brilliant answer. I had been passing lambdas to a variadic std::function arg without issue on Windows (Visual Studio 2015) but hit compile errors with gcc on Linux. By implementing the above solution, I can keep my code changes minimal and the look is fairly clean. – Danny S Mar 24 '21 at 01:31
14

As shown at Inferring the call signature of a lambda or arbitrary callable for "make_function", you can infer the calling signature of a lambda (or any other functor with a single calling signature) from its (single) 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 rather inflexible approach, though; as R. Martinho Fernandes says, it won't work for functors with multiple operator()s, nor for functors with templated operator() or for (C++14) polymorphic lambdas. This is why bind defers inference of its result type until the eventual call attempt.

Community
  • 1
  • 1
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • 2
    Oh jeez... I think I'll just stay away from lambdas for a while. They're becoming more trouble than they're worth. – retep998 Nov 13 '12 at 11:05
8

It is possible to get the needed std::function type for lambda using derivation, decltype, variadic templates and a few type traits:

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 like this:

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

PS: in my real case I then save this std::function object and its arguments inside a generic kernel objects that I can execute later on demand via virtual functions.

     

Viatorus
  • 1,804
  • 1
  • 18
  • 41
Alex Kosenkov
  • 145
  • 2
  • 5
3

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

auto sum = [](int a, int b){ return a+b; };
auto inc = std::bind( sum, _1, 1 );
assert( inc(1)==2 );
xtofl
  • 40,723
  • 12
  • 105
  • 192
  • My goal was to be able to do something like this `cout< – retep998 Nov 13 '12 at 10:30
  • @retep998: in your example code, your lambda captures nothing and therefore is convertible to a function pointer. I assume that you *don't* want a solution that relies on that? – Steve Jessop Nov 13 '12 at 10:42
  • @retep998: Other than the word `curry` vs. `std::bind` and the placeholder, how does the proposed solution differ from your request? `cout << std::bind([](int x, int y){ return x*y; },5,_1)(7)` – David Rodríguez - dribeas Nov 14 '12 at 05:18
  • 3
    Arguably `std::bind` is partial application (amongst other uses). There is an overlap in what both currying and partial application are useful for though. – Luc Danton Nov 14 '12 at 06:08
  • 1
    note: http://stackoverflow.com/questions/218025/what-is-the-difference-between-currying-and-partial-application – xtofl Nov 14 '12 at 12:35
3

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

That is an experiment I have written a month ago. The goal was to create a functor-like C++ template which emulates Haskell's partial calls closures, i.e. the automatic creation of a closure of m-n argumments when you call with n argumments a function with m parameters.

This is one example of what this experiment is cappable to 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 the different types of function entities, lambdas included:

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 comma operator to mmimic Haskell syntax, but you could change it to the call operator to achieve your goal syntax.

Your are completely free to do anything you want with the code (Check the license).

Manu343726
  • 13,969
  • 4
  • 40
  • 75
  • Note that my traits are very similar to the solutions proposed here. I was posting this only to show you a practical and working example of something similar to what you are trying to do. – Manu343726 Jun 05 '14 at 19:44
2

In C++17 there is the constructor type deduction. So you can save some typing for the std::function template arguments. This is not quite nothing, but a bit less.

template <typename R, typename...A>
void foo(std::function<R(A...)>) {}
int main() {
   foo(std::function([](){}));
}    
user2281723
  • 519
  • 1
  • 5
  • 16
1

Seven years later and probably the simplest solution then, still works today.

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

Usage

constexpr auto lama () { return "Lama"; } 

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

Lambda afficionados are served too

 auto cat = [] () constexpr { return "Cat"; } ;
 auto sneaky = user< cat >{} ;
 cout << boolalpha << sneaky.id() << endl ;
Chef Gladiator
  • 902
  • 11
  • 23
0

With lambda expressions that have explicit template parameter lists (C++20 feature), you can write the function much easier as shown below:

template <typename F,typename... T>
auto func(F f, T... values) {
    return f(values...);
}
int main() {
    auto result = func([]<typename... T>(T...args){
            return (...*args);
    },1,2,3,6,22);

    std::cout<<result<<"\n";
}
Saeed Masoomi
  • 1,703
  • 1
  • 19
  • 33
-1

with std::result_of, if you use only function (no class/struct, 'cause the declaration would be nothing like the std::function, and it really ugly),you can now make it like:


template <typename Func, typename ...Args>
std::result_of_t<Func(Args...)> func(Func function, Args... args) {
    /// now do your staff here
}
/// usage:
func([](){printf("lambda function\n"});
陈泽霖
  • 95
  • 6