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 cours
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; };
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?
The lambda code doesn't work for the same reason this doesn't work:
struct foo {
operator int*() const {
static int x;
return &x;
}
};
int* pint = foo{};
auto* pint2 = foo{}; // does not compile
or even:
template<class T>
void test(T*) {};
test(foo{});
The lambda has an operator that implicitly converts it to a (particular) function pointer, just like foo
.
auto
does not do conversion. Ever. Auto behaves like a class T
parameter to a template function where its type is deduced.
As the type on the right hand side is not a pointer, it cannot be used to initialize an auto*
variable.
Lambdas are not function pointers. Lambdas are not std::function
s. They are auto-written function objects (objects with an operator()
).
Examine this:
void (*ptr)(int) = [](auto x){std::cout << x;};
ptr(7);
it compiles and works in gcc (not certain if it is an extension, now that I think about it). However, what would auto* ptr = [](auto x){std::cout << x;}
supposed to do?
However, unary +
is an operator that works on pointers (and does nearly nothing to them), but not in foo
or a lambda.
So
auto* pauto=+foo{};
And
auto* pfun=+[](int x){};
Both work, magically.