Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

automatic decay of lambda to function pointer when passing to template function

Is there a way to make a lambda decay to a pointer, without explicitly casting to the right signature? This would tidy some code:

template<typename T> T call(T(*func)()){ return func(); }
int ptr(){ return 0; }
int main(){
    auto ret1 = call(ptr);
    auto ret2 = call((int(*)())([]{ return 0; }));
    auto ret3 = call([]{ return 0; });  //won't compile
}

It's evident that a call to call works only if the lambda decays to a pointer, but I'm guessing that that can happen only after the right function overload/template is chosen. Unfortunately I can only think of solutions that involve templates to make a lambda with any signature decay, so I'm back to square one.

like image 783
Lorenzo Pistone Avatar asked Mar 10 '14 11:03

Lorenzo Pistone


People also ask

Is lambda function a function pointer?

A lambda expression with an empty capture clause is convertible to a function pointer. It can replace a stand-alone or static member function as a callback function pointer argument to C API.

Is a C++ lambda a function pointer?

C++ Lambdas Conversion to function pointer This feature is mainly useful for using lambdas with APIs that deal in function pointers, rather than C++ function objects. Conversion to a function pointer is also possible for generic lambdas with an empty capture list.

What is the advantage of Replaceing function pointers Withh functors?

You often use functors instead - that is, classes that overload the operator () , so that they can be "called" as if they were functions. Functors have a couple of big advantages over function pointers: They offer more flexibility: they're full-fledged classes, with constructor, destructor and member variables.


2 Answers

You can change your lambda to use the unary + operator: +[]{ return 0; }

This works because unary plus can be applied to pointers, and will trigger the implicit conversion to function pointer.

like image 59
Simple Avatar answered Oct 05 '22 18:10

Simple


Why would you unnecessarily constrain yourself to function pointers without defaulted arguments and lambdas without captures, completely ruling out the huge family of functors (e.g. std::function, any results of std::bind and everything else that has a suitable operator())?

Better just broaden your function signature:

template <typename F> 
auto call(F func) -> decltype(func()) { 
  return func(); 
}

int ptr() { return 0; }

int g(int i = 0) {return i;}

int main() {
    auto ret1 = call(ptr);
    auto ret2 = call((int(*)())([]{ return 0; })); //tedious, but works
    auto ret3 = call([]{ return 0; });  //ok now.

    auto ret4 = call(g); //ok now!
    int i = 42;
    auto ret5 = call([=]{return i;}); //works, too!
    auto ret6 = call(std::bind(g, i)); //and so on...
}
like image 25
Arne Mertz Avatar answered Oct 05 '22 20:10

Arne Mertz