Reputation: 47
Is there any way to create variable that will be unique for some lambda function and will last between launches of lambda?
More careful description: I want lambda with variable initialized to some value, and that variable should last between launches:
std::function<void(void)> a=[]()
{
/*here we declare variable X and initialize it to 0*/;
std::cout<<X++;
};
a();a();
So this should print out 01
But also I need to be sure that "X" is unique for "a", so after previous part this
std::function<void(void)> b=a;
b();b();
should print out 01.
I tried using static variables, but they are shared between copies(so these two parts print out 0123).
So, is there any way to do it?
Upvotes: 2
Views: 70
Reputation: 275385
You want it to reset on copies. Make data that does this:
template<class T>
struct no_copy {
T init;
T current;
operator T&(){ return current; }
operator T const&()const{ return current; }
no_copy( T&& i ):init(i), current(init) {}
no_copy( no_copy const&o ):init(o.init), current(init) {}
no_copy( no_copy &&o ):init(std::move(o.init)), current(init) {}
};
template<class T>
no_copy<std::decay_t<T>> make_no_copy(T&& t){
return {std::forward<T>(t)};
}
Then, in C++14, easy:
std::function<void(void)> a=[X=make_no_copy(0)]()mutable
{
std::cout<<X++;
};
a();a();
prints out 01
.
In C++11:
auto X=make_no_copy(0);
std::function<void(void)> a=[X]()mutable
{
std::cout<<X++;
};
a();a();
it also works, but is a bit more ugly.
Other than a copy of X
existing outside of the lambda, the C++11 version is the same as the C++14 version in behavior.
Upvotes: 2
Reputation: 9343
Is using the copy constructor for "resetting" the only option? Shouldn't you be instead writing a factory function that emits fresh lambdas from the same initial environment?
Expecting that stuff A is different from stuff B after a copy is abuse of semantics.
auto make_counter() -> std::function<int()> {
return [x=0]() mutable { return x++; };
}
auto a = make_counter();
std::cout << a() << " " << a() << "\n";
auto b = make_counter();
std::cout << b() << " " << b() << "\n";
Upvotes: 0
Reputation: 118340
I don't think mutable lambdas are sufficient. The mutable capture will get copied, when you copy the function pointer, also copying the counter. My read of the question, is that each copy of the lambda should start with the initial mutable capture.
You need to capture a custom class, with a copy constructor, to do this:
#include <functional>
#include <iostream>
class my_class {
public:
int n=0;
my_class()
{
}
my_class(const my_class &b)
{
}
};
int main()
{
std::function<void(void)> a=
[my_class_instance=my_class()]()
mutable
{
std::cout << my_class_instance.n++;
};
a();
a();
auto b=a;
b();
b();
}
The result from this is:
0101
Without a helper class, the equivalent code using only mutable lambdas will produce a
0123
My read of the question, is that the former behavior is desired.
Upvotes: 3