54

According to the C++11 standard, lambda expressions may use variables in the enclosing scope, by means of the capture list, the parameter list or both.

So, let's look to two versions of the same code.

1) With capture

int x = 4;

cout << "With capture  : Factorial of " << x << " = " << [x]() // <= Capture
{
    int r = 1;
    for (int i = x; i > 1; i--) r = r * i;
    return r;
}() << endl;

2) With parameter

int x = 4;

cout << "With parameter: Factorial of " << x << " = " << [](int x) // <= Parameter
{
    int r = 1;
    for (int i = x; i > 1; i--) r = r * i;
    return r;
}(x) << endl;

The output is:

With capture  : Factorial of 4 = 24
With parameter: Factorial of 4 = 24

Since we can pass parameters to lambdas in the parameter list (just as with any C++ function), why do we need the capture list?

Can someone show me cases where parameter list doesn't work and only capture list does?

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
Xico d'Abrolha
  • 541
  • 1
  • 4
  • 4

2 Answers2

36

For example using stl algorithms:

std::vector<int> items;
int factor;
auto foundItem = std::find_if(items.begin(), items.end(), 
[&factor](int const& a) 
{ 
   return a * factor == 100; 
});

In this case you're called in the lambda for every item in the container and you return if the value multiplied by a captured factor is 100. The code doesn't make much sense, it's just to show you an example where capture and parameter lists matter.

dau_sama
  • 4,247
  • 2
  • 23
  • 30
  • 4
    can't we pass both ints 'a' and 'factor' in the parameter list and let the capture empty? – Xico d'Abrolha Feb 23 '15 at 09:14
  • 7
    @Xicod'Abrolha How? You're not calling the lambda, `std::find_if` is doing it. How would you make it call the function differently? – Angew is no longer proud of SO Feb 23 '15 at 09:28
  • 3
    no Xico, you can't! in the find_if code somewhere you have something that calls your lambda (or function) like this: handler(value); for each value in the range begin/end. – dau_sama Feb 23 '15 at 09:34
  • Thank you dau_sama and Angew. At last I understand the need of capture lists. Your help was more valuable than the pile of books I've read and the googling I've made. SO requires 15 rep to mark the answer as helpful. I have only 11 rep. Nevertheless, thank you. – Xico d'Abrolha Feb 23 '15 at 10:14
  • 2
    @Xicod'Abrolha: you don't need 15 rep to accept an answer, that's how much rep dau_sama would get if you accept it. There is no minimum rep for accepting an answer (and it will gain you 2 rep). – Mat Feb 23 '15 at 11:25
  • To be precise, `std::find_if` accepts only UnaryPredicate – ripfreeworld Jun 07 '22 at 20:48
16

The point is that with capture, you can keep a state (just as a hand written class with operator() ) in a function-like object. @dau_sama gives a good answer. Here is another example:

#include <iostream>
using namespace std;

int main() {

  const auto addSome = [](double some){
    return [some](double val){ return some+val; } ;
  };

  const auto addFive = addSome(5);

  std::cout << addFive(2) << std::endl;
}
Johan Lundberg
  • 26,184
  • 12
  • 71
  • 97