user40129
user40129

Reputation: 833

How to derive parameters from a lambda expression?

How can I change my template function definition so that it will work?

Consider the following code:

#include <iostream>

#include <functional>

using namespace std;

void callthis(function<void()> func){
    func();
}

void callthis(function<void(int)> func, int par){
    func(par);
}


template<typename... Args>
void callthistemp(function<void(Args...)> func, Args&&... args){
    func(std::forward<Args>(args)...);
}

int main(){

callthis([](){cout << "hello " << endl;}); // (1)
callthis([](int x)->void{cout << "hello " << x << endl;},1); //(2)
function<void(int)> xx = [](int x){cout << "hello" << endl;};
callthistemp(xx,1);//(3)

//callthistemp([](int x)->void{cout << "hello" << endl;},1); //(4)
//callthistemp<int>([](int x)->void{cout << "hello" << endl;},1); //(5)
}

The first three cases all works well, but the last two do not compile, and gives the error

lambdatemplate.cpp: In function ‘int main()’:
lambdatemplate.cpp:29:66: error: no matching function for call to ‘callthistemp(main()::__lambda3, int)’
     callthistemp<int>([](int x)->void{cout << "hello" << endl;},1); //(5)
                                                                  ^
lambdatemplate.cpp:29:66: note: candidate is:
lambdatemplate.cpp:17:6: note: template<class ... Args> void callthistemp(std::function<void(Args ...)>, Args&& ...)
 void callthistemp(function<void(Args...)> func, Args&&... args){
      ^
lambdatemplate.cpp:17:6: note:   template argument deduction/substitution failed:
lambdatemplate.cpp:29:66: note:   ‘main()::__lambda3’ is not derived from ‘std::function<void(Args ...)>’
     callthistemp<int>([](int x)->void{cout << "hello" << endl;},1); //(5)

Upvotes: 3

Views: 385

Answers (2)

Puppy
Puppy

Reputation: 146900

A lambda is not a std::function for any template arguments. This is why there is a problem. The compiler note says it all.

main()::__lambda3’ is not derived from ‘std::function<void(Args ...)>’

This is what would be required for the call to work. You will have to construct a temporary or perhaps create a make_function kind of thing. The first three work because you are not trying to pass a lambda as a templated std::function.

Upvotes: 1

mmmmmmmm
mmmmmmmm

Reputation: 15513

How about

template<typename L, typename... Args>
void callthistemp(L const &func, Args&&... args)
{
  func(std::forward<Args>(args)...);
}

There is no need to wrap your lambda into a (sometimes expensive) std::function when using templates. (expensive means that it may use heap allocations which is not necessary in this case).

Upvotes: 5

Related Questions