Difference between capturing and passing an argument in lambda functions

16.1k Views Asked by At

I understand the lambda function and the purpose of it in c++ 11. But i do not understand the difference between "Capturing the value" and "Passing an argument". For Instance..

#include <iostream>
#include <functional>
using namespace std;

int add(int a,int b){
    return a+b;
}

int main(int argc, char** argv){

    function <int(int,int)> cppstyle;
    cppstyle = add;

    auto l = [] (function <int(int,int)> f,int a, int b) {return f(a,b);};

    cout << l(cppstyle,10,30) <<"\n";   
}

The output of the code above is same as the code below..

#include <iostream>
#include <functional>
using namespace std;

int add(int a,int b){
    return a+b;
}

int main(int argc, char** argv){

    function <int(int,int)> cppstyle;
    cppstyle = add;

    auto l = [cppstyle] (int a, int b) {return cppstyle(a,b);};

    cout << l(10,30) <<"\n";    
}

Is "capturing a value" similar to "passing a value as an argument"? or capture has some special meaning?

3

There are 3 best solutions below

3
On BEST ANSWER

The difference between a captured argument and a passing argument could be seen with an analogy. Consider the following function object:

struct Capture {
  int &i;
  int const j;
public:
  Capture(int &_i, int &_j) : i(_i), j(_j) {}
  int operator()(int const a, int const b) {
    i *= j;
    return a * b;
  }
};

In function object class Capture there are two member variables i and j. There's also overloaded operator() which takes two input arguments. Now consider the following lambda:

int i, j;
[&i, j](int const a, int const b) {
  i *= j;
  return a * b;
};

The member variables of class Capture are in analogy with the lambda capture (i.e., [&i, j]), whereas input arguments of overloaded operator() a and b are in analogy with input arguments a and b of the lambda shown above.

That is, if you consider a lambda as a function object, its capture is the state of the function object (i.e., its member variables) whereas its input arguments would be the input arguments of the overloaded operator().

2
On

At a higher level, you capture the data you know now, and you pass in the data you don't have until you need to make the call.

For instance, let's say you wanted to add a constant to every number in a vector. Your could write it like (caution: untested):

void Add(std::vector<int>& v, int i)
{
    std::for_each(std::begin(v), std::end(v), [i](int& j){ j += i; });
}
3
On

The capture of i value is set when the lambda was defined, while when i is passed as argument (j), it is changing in the loop.

#include <iostream>
using namespace std;

int main(int argc,char **argv)   {
    auto i=5;
    auto f = [=](int j) {cout<<"capture i="<<i<<", passing i as j="<<j<< endl; };
    while (i<30) {
        i += 10;
        f(i);
    }
}

--- This will be the output:

lambda capture i=5, passing i as argument j=15

lambda capture i=5, passing i as argument j=25

lambda capture i=5, passing i as argument j=35