Lambda expressions
==================


since C++11
extended in C++14




#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v;
    for(int i = 0; i < 10; ++i)
        v.push_back(i);

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
    cout << endl;
    return 0;
}


$ g++ l.cpp
$ ./a.out
0 1 2 3 4 5 6 7 8 9
$


[]        lambda-introducer
(int n)   lambda parameter declaration
{ ... }   compound statement



Lambda expressons define classes and construct objects.
The program above is equivalent to:


#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

struct LambdaFunctor
{
    void operator() (int n) const { cout << n << " "; }
};

int main()
{
    vector<int> v;
    for(int i = 0; i < 10; ++i)
        v.push_back(i);

    for_each(v.begin(), v.end(), LambdaFunctor());
    cout << endl;
    return 0;
}



Definitions from Meyers' Effective Modern C++:

Lambda expression:  [](int n) { cout << n << " "; }
Closure: runtime object created from lambda. May hold captured variables.
Closure class: the type of the closure object.



The expression can contain multiply statements


#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v;
    for(int i = 0; i < 10; ++i)
        v.push_back(i);

    for_each(v.begin(), v.end(), [](int n) {
    		    cout << n ;
    		    if ( n % 2 )
    		        cout << ":odd ";
		    else
    		        cout << ":even ";
 					   });
		        cout << endl;
    return 0;
}


0:even 1:odd 2:even 3:odd 4:even 5:odd 6:even 7:odd 8:even 9:odd


If the lambda expession has return value, than the return type
is automatically deduced from that expression:


int main()
{
    vector<int> v;
    for(int i = 0; i < 10; ++i)
        v.push_back(i);

    deque<int> d;

    transform(v.begin(), v.end(), front_inserter(d), [](int n) {return n*n;} );

    for_each(d.begin(), d.end(), [](int n) { cout << n << " "; });

    cout << endl;
    return 0;
}


81 64 49 36 25 16 9 4 1 0



Sometimes it is not easy to deduce the return type. We can explicitly
specify the return type.



#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
#include <deque>

using namespace std;

int main()
{
    vector<int> v;
    for(int i = 0; i < 10; ++i)
        v.push_back(i);

    deque<double> d;

    transform(v.begin(), v.end(), front_inserter(d),
		    [](int n) -> double  { return n / 2.0; } );

    for_each(d.begin(), d.end(), [](double n) { cout << n << " "; });

    cout << endl;
    return 0;
}


4.5 4 3.5 3 2.5 2 1.5 1 0.5 0


-> double    is the lambda return type clause
             (it is on the right, because [] should be on left for parsing)



[] means, that the lambda is "stateless", but we can "capture" local variables


#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v;
    for(int i = 0; i < 10; ++i)
        v.push_back(i);

    int x = 0;
    int y = 0;
    cin >> x >> y;

    v.erase( remove_if(v.begin(),
	               v.end(),
                       [x,y](int n) { return x < n && n < y; }
     		      ),
	     v.end()
	   );

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

    cout << endl;
    return 0;
}


3 6
0 1 2 3 6 7 8 9


We passed the x and y parameters by value. Basically it is equivalent:


struct LambdaFunctor
{
public:
    LambdaFunctor(int a, int b) : m_a(a), m_b(b) { }
    bool operator()(int n) const { return m_a < n && n < m_b; }
private:
    int m_a;
    int m_b;
};

// ...

 v.erase( remove_if(v.begin(),v.end(),LambdaFunctor(x,y)), v.end());


The x and y parameters are copied and being stored in the function object.
We cannot modify the captured values because the operator() in functor is
const. It is a "real" copy, therefore the modification of x and y is not
reflected inside the lambda.



[=]    default-capture lambda introducer. Captures all locals by value.


#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v;
    for(int i = 0; i < 10; ++i)
        v.push_back(i);

    int x = 0;
    int y = 0;
    cin >> x >> y;

    v.erase( remove_if(v.begin(),
	               v.end(),
                       [=](int n) { return x < n && n < y; }
     		      ),
	     v.end()
	   );

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

    cout << endl;
    return 0;
}


3 6
0 1 2 3 6 7 8 9



Variables captured by value by lambda are really stored in the object:


#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v;
    for(int i = 0; i < 10; ++i)
        v.push_back(i);

    int x = 0;
    int y = 0;

    auto f = [=](int n) { auto sz = v.size(); return x < n && n < y; };

    v.erase( remove_if(v.begin(),
	               v.end(),
                       f
     		      ),
	     v.end()
	   );

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

    cout << endl;
    cout << "size of f = " << sizeof(f) << endl;
    return 0;
}

$ ./a.out
0 1 2 3 4 5 6 7 8 9
size of f = 32




Lambda expressions are const by default but we can manage to modify x and y.
Note, that modification of prev does not update local prev variable.


#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v;
    for(int i = 0; i < 10; ++i)
        v.push_back(i);

    int prev = 0;
    for_each(v.begin(), v.end(), [=](int& r) mutable {
		            const int oldr = r;
    			    r *= prev;
   		            prev = oldr;
   			 });

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

    cout << "prev = " << prev << endl;
    return 0;
}


0 0 2 6 12 20 30 42 56 72 prev = 0


Capture by reference


#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v;
    for(int i = 0; i < 10; ++i)
        v.push_back(i);

    int prev = 0;
    for_each(v.begin(), v.end(), [&prev](int& r) mutable {
			            const int oldr = r;
	    			    r *= prev;
	    		            prev = oldr;
      			     });

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

    cout << "prev = " << prev << endl;
    return 0;
}


0 0 2 6 12 20 30 42 56 72 prev = 9


[&]         Capture everything by reference

[=, &x, &y] Capture everything by value but x and y which capured by reference

[&, x, y]   Capture everything by reference but x and y which capured by value




#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

struct X
{
    int s;
    vector<int> v;
    void print() const
    {
        for_each(v.begin(), v.end(), [](int n) { cout << n*s << " "; });
    }
};

int main()
{
    X x;
    x.s = 2;
    for(int i = 0; i < 10; ++i)
        x.v.push_back(i);

    x.print();
    return 0;
}


$ g++ l10.cpp
l10.cpp: In lambda function:
l10.cpp:15:60: error: ‘this’ was not captured for this lambda function



#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

struct X
{
    int s;
    vector<int> v;
    void print() const
    {
        for_each(v.begin(), v.end(), [this](int n) { cout << n*s << " "; });
    }
};

int main()
{
    X x;
    x.s = 2;
    for(int i = 0; i < 10; ++i)
        x.v.push_back(i);

    x.print();
    return 0;
}


- this always captured by value
- you can implicitly capture this with [=]
- capturing this can be dangerous:
    (not smart) pointer, pointed object lifetime may already finished...



global variables, static data members could be used
but they are not captured!


#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

int ii = 5;

int main()
{
    vector<int> v;
    for(int i = 0; i < 10; ++i)
        v.push_back(i);

    int x = 0;
    int y = 10;

    auto f = [=](int n) { if (x < n-ii && n-ii < y)
                            cout << n << " ";
                        };

    for_each(v.begin(), v.end(), f);
    cout << endl;

    ii = 1;

    for_each(v.begin(), v.end(), f);
    cout << endl;
    return 0;
}


$ ./a.out
6 7 8 9
2 3 4 5 6 7 8 9




We can define "nullary" lambdas


#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v;
    int i = 0;

    generate_n(back_inserter(v), 10, [&] { return i++; } );

    for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
    return 0;
}


0 1 2 3 4 5 6 7 8 9



Or you can write [&]() { return i++; }

Lambdas can be stored in std::functional


#include <algorithm>
#include <functional>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

void doit(const vector<int>& v, const function<void (int)>& f)
{
    for_each(v.begin(), v.end(), f);
    cout << endl;
}

int main()
{
    vector<int> v;
    int i = 0;

    generate_n(back_inserter(v), 10, [&] { return i++; } );

    doit(v, [](int n) { cout << n << " "; });

    const function<void (int)>& ff = [](int n) { cout << n << " "; };
    doit(v, ff);

    return 0;
}


0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9


/* const */ int i = some_default_value; // can't do it const
                                        // since value depends
if(someConditionIstrue)                 // on some condition.
{
    // Do some operations and calculate the value of i; 
    i = // some calculated value; 
}
int x = i; // use i

// But unfortunately in this case there is no way to guarantee 
// it is used as a constant, so now if some one comes and does

i = 10; // This is valid





const int i = [&]{

    int i = some_default_value;

    if(someConditionIstrue)
    {
        // Do some operations and calculate the value of i; 
        i = // some calculated value; 
    }
    return i;

} (); // note: () invokes the lambda!




Generalized lambdas in C++14:
=============================



auto L = [](const auto& x, auto& y){ return x + y; };

means:

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    {
        return x + y;
    }
} L;




Init capture or Generalized lambda capture, since C++14
=======================================================



auto up = std::make_unique<X>();

auto func = [up = std::move(up)] { return up->f(); }
              ^              ^             ^
              |              |             |
       this is called       this is      here we
      inside the lambda     captured     use inside


or:



auto func = [up = std::make_unique<X>()] { return up->f(); }



auto f = [](auto x) { return func(func2(x)); }


class UnnamedFunctor
{
public:
  template <typename T>
  auto operator()(T x) cont
  {
    return func(func2(x));
  }
};


Perfect forwarding:


class UnnamedFunctor
{
public:
  template <typename T>
  auto operator()(T&& x) cont
  {
    return func(func2(std::forward<T&&>x));
  }
};


auto f = [](auto&& x) { return func(func2(std::forward<???>(x))); }



auto f = [](auto&& x) { return func(func2(std::forward<decltype(x)>(x))); }



auto f = [](auto&&... params)
{
  return func(func2(std::forward<decltype(params)>(params)... ));
}



Be care with capturing this
===========================



#include <algorithm>
#include <functional>
#include <memory>
#include <iostream>
#include <ostream>
#include <vector>

using namespace std;

std::function<void (int)> f;

struct X
{
  X(int i) : ii(i) {}
  int ii;
  void addLambda()
  {
    f = [=](int n) { if (n == ii) cout << n;
                     else         cout << ii;
                   };
  }
};

int main()
{
  {
    std::unique_ptr<X> up = std::make_unique<X>(4);
    up->addLambda();
    f(4);
  }
  f(4);
  return 0;
}