I'm implementing a lambda as variable. In C 20 it works this way:
auto lambda = []<typename T>() -> const T& {
...
};
Now I want to store this kind of lambda function as a member variable of a struct:
struct A {
??? m_lambda;
A(??? lambda) : m_lambda(lambda) {}
};
Is there a way to do this?
CodePudding user response:
You store any templated lambda the same ugly way you store ordinary ones:
constexpr auto lambda = []<typename T>() {};
struct Foo{
decltype(lambda) m_lambda;
Foo():m_lambda(lambda){}
};
This works because it is operator()
that is actually templated, not the automatically-generated lambda type.
If you do not rely on inlining any calls to the lambda (for performance), you can store it in std::function<Ret(Args)>
for correct signature.
std::function
is also the only* option if the lambda cannot be defined before Foo
as seems to be the case of your constructor.
struct A {
std::function<void()> m_lambda;
// Not a lambda per se.
A(std::function<void()> lambda) : m_lambda(std::move(lambda)) {}
};
The above is not a lambda exactly because it doesn't really make sense most of the time to take a lambda as parameter as each has a distinct type making the argument effectively redundant.
*One can always make A
a class template and use CTAD for deduction, not sure you want to go that way though.
CodePudding user response:
In c 20 you can do:
struct Foo
{
decltype([] <class T> () {/* ... */ }) m_lambda {};
};
That being said it doesn't make any sense to store a lambda as a data member. Lambdas cannot change so a method is the simple, preferred alternative.
CodePudding user response:
Since your lambda is templated, you will need to contain the lambda directly in your object.
Fortunately, it's quite easy to do in C 20 (and C 17):
auto lambda = []<typename T>() -> const T& {
// ...
};
template<typename L> // <-- L is the lambda type
struct A {
L m_lambda;
A(L lambda) : m_lambda(lambda) {}
void foo() {
// Can call using many types using the template
int const& a = m_lambda.template operator()<int>();
float const& b = m_lambda.template operator()<float>();
}
};
int main() {
auto my_a = A{lambda}; // construct using the lambda and CTAD
my_a.foo();
}
If on the contrary you need A
to only call one version of the template, you can wrap the lambda in another lambda:
struct A {
std::function<int const&()> m_lambda;
A(auto const& lambda) : m_lambda{
[lambda]{ return lambda.template operator()<int>(); }
} {}
void foo() {
// Can call and get a int const reference back
int const& a = m_lambda();
}
};