Disclaimer: Do not use the code in this question. It invokes undefined behaviour. The core statement of the question, whether the compiler generates a new type for each lambda, and the corresponding answer remain valid.
To take get a function pointer to a lambda with a capture I came up with the following trick:
auto f = [&a] (double x) { return a*x; };
static auto proxy = f;
double(*ptr)(double) = [] (double x) { return proxy(x); };
// do something with ptr
I assign the lambda with a capture (which might be a function parameter) to a static variable inside the function, so I do not have to capture it when using it in the other lambda. The other captureless lambda can then happily decay to a function pointer which I can pass to some shared library.
Now one could attempt to generalize this:
template < typename F >
decltype(auto) get_ptr(F f)
{
static auto proxy = f;
return [] (auto ... args) { return proxy(args...); };
}
However, as proxy is a static variable it will be overwritten on each call to the function. Because it is a template, I think that it will be overwritten only when I call the same instantiation, i.e. each instantiation has it's own static proxy.
Nevertheless, the following works:
#include <cassert>
template < typename F >
decltype(auto) get_ptr(F f)
{
static auto proxy = f;
return [] (auto ... args) { return proxy(args...); };
}
int main()
{
auto f1 = [ ](double,double) { return 1; };
auto f2 = [=](double,double) { return 2; };
auto f3 = [&](double,double) { return 3; };
auto f4 = [&](double,double) { return 4; };
auto f5 = [ ](double,double) { return 5; };
int(*p1)(double,double) = get_ptr(f1);
int(*p2)(double,double) = get_ptr(f2);
int(*p3)(double,double) = get_ptr(f3);
int(*p4)(double,double) = get_ptr(f4);
int(*p5)(double,double) = get_ptr(f5);
assert( p1(0,0) == 1 );
assert( p2(0,0) == 2 );
assert( p3(0,0) == 3 );
assert( p4(0,0) == 4 );
assert( p5(0,0) == 5 );
}
This looks suspicious as for get_ptr(f1) and get_ptr(f5) one might expect the same types to be deduced. However, lambdas are compiler generated structs and it seems as if the compiler would generate a different type for each lambda, regardless of whether previous lambdas look like they could be reused.
So the above trick would be extremely useful for me under the condition that the compiler will definitely generate a different type for each lambda. If this is not the case the generalisation of my hack is useless.
From the draft spec (n3376 specifically), 5.1.2.3 (emphasis mine).
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type...
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