I would like to create a function that generates lambdas, where each of the lambdas has its own static variable. However, counter to what I thought would happen, the static variable seems to be shared between instances. For instance,
#include <iostream>
auto make_lambda(){
return [](){
static auto count = 0;
return count++;
};
}
int main() {
auto a = make_lambda();
auto b = make_lambda();
std::cout << &a << ", " << a() << std::endl;
std::cout << &b << ", " << b() << std::endl;
}
returns
0x7ffc229178df, 0
0x7ffc229178de, 1
So a
and b
seem to be unique instances, but are sharing that static count. I thought that I would see, and indeed want to see, something like
0x7ffc229178df, 0
0x7ffc229178de, 0
live demo
What is the simplest way to make sure that the lambdas each have their own static variable?
Ditch the static variable and use an extended lambda capture:
#include <iostream>
auto make_lambda(){
return [count = 0]() mutable {
return count++;
};
}
If you want different lambda instances to share state with their respective copies but not between them, you can use a std::shared_ptr
instead:
auto make_lambda(){
return [count = std::make_shared<int>(0)]() mutable {
return (*count)++;
};
}
You can leverage the fact that instantiated functions, and the templated entities they enclose, have their own copies of static variables defined in the function. Turning make_lambda
into a template...
template<int>
static auto make_lambda(){
return [](){
static auto count = 0;
return count++;
};
}
... will generate a new static variable for each new template argument, unique to the TU (on account of the function template itself being static
):
auto a = make_lambda<0>();
auto b = make_lambda<1>();
std::cout << &a << ", " << a() << std::endl;
std::cout << &b << ", " << b() << std::endl;
Which is not quite the syntax you wanted, but gets the job done. If you don't mind involving the preprocessor and potentially compiler extensions, you can get the simple function call syntax with a helper macro.
#define make_lambda() make_lambda<__COUNTER__>()
where __COUNTER__
is a GCC extension that expands to a new number every time expansion is required in any single TU.
You can pass a variable by value to the lambda. Moreover you have to make the lambda mutable so you'll be able to modify the value during execution. Normally labdas are like a const methods.
auto make_lambda(){
int count = 0;
return [count]() mutable {
return count++;
};
}
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