12

I have a basic lambda that looks like this:

auto l = [](){
  int i = 0;
  cout << i++;
}

Calling this a bunch of times, will keep printing 0. How can I retain i? Can I do this without functors?

Hiura
  • 3,500
  • 2
  • 20
  • 39
val
  • 729
  • 6
  • 19

4 Answers4

25

Depending on what you want to do with this lambda, you might consider the following alternative:

auto exec = [i = 0]() mutable { cout << ++i << ' '; };
exec();  // 1
exec();  // 2
auto exec2 = exec; // copy state of lambda
exec2(); // 3
exec();  // 3

Using []() { static int i = 0; cout << ++i << ' '; }; instead will result in the sequence 1 2 3 4 being printed.

Live example

Hiura
  • 3,500
  • 2
  • 20
  • 39
21

Try to think of a lambda as a class with an operator(). How would you retain state in a class? Have a member. Captures are the equivalent here.

#include <iostream>
auto l = [i=0]()mutable{
  std::cout << i++;
};
auto l2=l;
int main(){
  l(); // 0
  l(); // 1
  l(); // 2
  l2(); // 0
  l2(); // 1
  l(); // 3
  std::cout << '\n';
}
Marc Glisse
  • 7,550
  • 2
  • 30
  • 53
4
 auto l = [](){
   static int i = 0;
// ^^^^^^
   cout << i++;
 }

should fix your concerns.

In general functions cannot retain inner state without using a local static variable. There's no difference with using lambdas actually.


If you want to count copies, you can use an ordinary functor class implementation as @Revolver_Ocelot suggested.

Community
  • 1
  • 1
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • just as a side question, if i'd want to make a copy of l, wouldnt that copy keep the same i variable as l? – val Jun 26 '16 at 10:45
  • 1
    @val Yes, it would keep it, since lambdas of the same type all share this instance of `i`. – πάντα ῥεῖ Jun 26 '16 at 10:46
  • is there a way each instance of l could have its own version of i that they can work with? – val Jun 26 '16 at 10:50
  • @val There was an interesting question about the values of [inheriting lambdas](http://stackoverflow.com/questions/38024024/what-does-it-mean-to-inherit-from-lambda?s=1|1.3089). I don't know if this helps you into the direction you want. – πάντα ῥεῖ Jun 26 '16 at 10:53
  • Lambdas should be passed by copy (the standard library always passes callable objects by copy). You wouldn't be able to if each instance had its own copy of i. – n. m. could be an AI Jun 26 '16 at 11:03
  • 2
    @val if you want each copy to have own value, you should write stateful functor yourself (lambda is actually just a syntax sugar for that). – Revolver_Ocelot Jun 26 '16 at 11:05
  • `mutable` keyword helps storing the state in a lambda – Oleg Zhylin Mar 05 '20 at 14:03
  • BE VERY CAREFUL using a local static. It appears the the capture is not re-performed everytime the lambda is created. The lambda appears to be compiled as if it was a global scope function and the static is not re-initialized everytime the lambda is created. This means results in different behavior between using a static and using the newer mutable lambda: https://github.com/microsoft/STL/issues/885#issuecomment-641328578 – Stephen Eckels Jun 09 '20 at 14:33
2

If you want i to retain its value then you have three options:

  1. Declare i as a global variable (Bad).
  2. Pass previous value of i to the function every time (Better).
  3. Declare i as a static variable (Best).

    auto l = []() { static int i = 0; cout << i++ << endl; };
    l(); l(); l();
    

    This will give as output:

    0
    1
    2
    
LogicStuff
  • 19,397
  • 6
  • 54
  • 74
Shubham Jain
  • 1,864
  • 2
  • 14
  • 24