Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Obtaining function pointer to lambda?

I want to be able to obtain a function pointer to a lambda in C++.

I can do:

int (*c)(int) = [](int i) { return i; }; 

And, of course, the following works - even if it's not creating a function pointer.

auto a = [](int i) { return i; }; 

But the following:

auto *b = [](int i) { return i; }; 

Gives this error in GCC:

main.cpp: In function 'int main()': main.cpp:13:37: error: unable to deduce 'auto*' from '<lambda closure object>main()::<lambda(int)>{}'      auto *b = [](int i) { return i; };                                       ^ main.cpp:13:37: note:   mismatched types 'auto*' and 'main()::<lambda(int)>' 

It seems arbitrary that a lambda can be converted to a function pointer without issue, but the compiler cannot infer the function type and create a pointer to it using auto *. Especially when it can implicitly convert a unique, lambda type to a function pointer:

int (*g)(int) = a; 

I've create a little test bed at http://coliru.stacked-crooked.com/a/2cbd62c8179dc61b that contains the above examples. This behavior is the same under C++11 and C++14.

like image 794
oconnor0 Avatar asked Jun 08 '16 18:06

oconnor0


People also ask

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 type of lambda expression C++?

The type of a lambda expression is unspecified. But they are generally mere syntactic sugar for functors. A lambda is translated directly into a functor.


2 Answers

This fails:

auto *b = [](int i) { return i; }; 

because the lambda is not a pointer. auto does not allow for conversions. Even though the lambda is convertible to something that is a pointer, that's not going to be done for you - you have to do it yourself. Whether with a cast:

auto *c = static_cast<int(*)(int)>([](int i){return i;}); 

Or with some sorcery:

auto *d = +[](int i) { return i; }; 
like image 152
Barry Avatar answered Oct 12 '22 22:10

Barry


Especially when it can implicitly convert a unique, lambda type to a function pointer:

But it cannot convert it to "a function pointer". It can only convert it to a pointer to a specific function signature. This will fail:

int (*h)(float) = a; 

Why does that fail? Because there is no valid implicit conversion from a to h here.

The conversion for lambdas is not compiler magic. The standard simply says that the lambda closure type, for non-capturing, non-generic lambdas, has an implicit conversion operator for function pointers matching the signature of its operator() overload. The rules for initializing int (*g)(int) from a permit using implicit conversions, and thus the compiler will invoke that operator.

auto doesn't permit using implicit conversion operators; it takes the type as-is (removing references, of course). auto* doesn't do implicit conversions either. So why would it invoke an implicit conversion for a lambda closure and not for a user-defined type?

like image 43
Nicol Bolas Avatar answered Oct 12 '22 22:10

Nicol Bolas