C++ standard has a below statement:
The closure type for a non-generic lambda-expression with no lambda-capture whose constraints (if any) are satisfied has a conversion function to pointer to function with C++ language linkage (10.5) having the same parameter and return types as the closure type’s function call operator.
To understand the statement much better, I used the cppinsights to see what the clang compiler says for the below function.
#include <iostream>
using test = void (*)(int);
int main()
{
test t = [](int arg) { std::cout << arg << std::endl; };
}
cppinsights translates the function as:
#include <iostream>
using test = void (*)(int);
int main()
{
class __lambda_7_11
{
public: inline void operator()(int arg) const
{
std::cout.operator<<(arg).operator<<(std::endl);
}
public: using retType_7_11 = void (*)(int);
inline operator retType_7_11 () const
{
return __invoke;
}
private: static inline void __invoke(int arg)
{
std::cout.operator<<(arg).operator<<(std::endl);
}
} __lambda_7_11{};
using FuncPtr_7 = test;
FuncPtr_7 t = static_cast<void (*)(int)>(__lambda_7_11.operator __lambda_7_11::retType_7_11());
}
As usual, the compiler generates an anonymous class with operator() overloaded along with "conversion function to pointer to function" as specified by the standard.
What I don't understand is that why a "static __invoke" function is generated and the "conversion function" is internally calling "__invoke" (directly as a function pointer) without any parameter which is expected by "__invoke"?
What I don't understand is that why a
static __invokefunction is generated and the "conversion function" is internally calling__invoke(directly as a function pointer) without any parameter which is expected by__invoke?
The conversion function does not "internally call" __invoke, it just returns __invoke, i.e., a pointer to a static member function. Remember that the difference between static and non-static member functions is that the former is not bound to a specific instance of that class, and can hence be treated as ordinary function pointers, as opposed to pointers to members. Have a look at the following example:
struct Test {
void f();
static void g();
};
void (Test::*f)() = &Test::f; // pointer to instance-specific member fct.
void (*g)() = &Test::g; // ordinary function pointer
void (*h)() = Test::g; // no ampersand, this is implicitly a function pointer
The latter is what you intend the result of the conversion to be, and what cppinsights shows you is nothing but a technique to implement this conversion: as the lambda expression has an empty closure, the function object generated by the compiler has no state, and a member function of an object with no state can be a static member function that can bind to an ordinary function pointer.
Cppinsights is correct in what it does. It returns the function pointer iso calling the function.
It would have been more readable if it would been writen the following way:
inline operator retType_7_11 () const
{
return &__invoke;
}
However, the & ain't required in this case.
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