Sorry, it's a long-winded question, but let me break it down:
Does the C++ standard guarantee that:
void (*Ptr)(void) = [] {};
return Ptr;
will still be defined behaviour?
I understand that, for a closure, it will be defined, because that closure object is moved/copied by value; but, while I know a 'regular' function has infinite/no lifetime, does the target of Ptr have the same? Or is it destroyed and recreated with each instantiation of the lambda?
The reason I care is, I can't use lambdas as callbacks if not. I want to know.
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.
A lambda object must not outlive any of its reference captured objects. Lambda expressions may capture objects with automatic storage duration from the set of enclosing scopes (called the reaching scope) for use in the lambda's function body.
Objects have lifetimes; functions do not. Functions don't live or die; they always exist. As such, a function cannot go "out of scope", nor can the function being pointed to by a previously valid function pointer vanish. Regardless of where they come from, function pointers are always valid.
Now, this ignores dynamic loading and so forth, but that's extra-standard behavior.
The function pointer you get back from a lambda is a function pointer. It's not special or magic. It therefore behaves no differently from any other function pointer.
Is it possible that the result of conversion to void (*)() points to something which invokes a member function bound to some object?
That's a much more complex question. One which the C++17 standard seems rather under-specified about, but which C++20 is much more clear on.
The C++17 standard only says:
the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.
What "the same effect" means exactly is the question. One could argue that "the same effect" means doing what the function call operator would have done, executing the same sequence of statements. One could also argue that "the same effect" would mean invoking the closure object itself.
The latter case may sound difficult to implement, but remember that compiler magic can be employed. The closure could return an instance-specific function pointer, allocated by the closure upon request. Or some-such.
The C++20 standard is much more clear, in part thanks to the fact that capture-less lambdas can be default constructed:
the address of a function F that, when invoked, has the same effect as invoking the closure type's function call operator on a default-constructed instance of the closure type.
So as of C++20, the standard makes it clear that invoking the function pointer is independent of the existence of the lambda object which created it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With