jammer312
jammer312

Reputation: 47

Lambda-specific variable

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

Answers (3)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

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.

live example

Upvotes: 2

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

Sam Varshavchik
Sam Varshavchik

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

Related Questions