Introduction to C++ 11 Series – Part 8, Lambda Expression or Functions

April 1, 2013

One of the most important features of C++ 11 is the addition of Lambda, an inline function mechanism (and a closure).

Motivation

The first motivation is to make this a valid C++ code:

[](){}();

Smile

There are many reasons to use lambda and functional programing; for example, STL algorithms use function or functor objects. STL <functional> provides a set of functors such as plus, minus, less, equal_to, etc. Most of these functors are binary functions, i.e. they take two parameters. To use a predefined binary functor in an STL algorithm, you need to bind one of the functor arguments to a predefined value. For example to find the first element whose value is greater than 10, you can write this code:

 

 

#include "stdafx.h"

#include <algorithm>

#include <functional>

#include <iostream>

#include <vector>

 

using namespace std;

 

int _tmain(int argc, _TCHAR* argv[])

{

     vector<int> v;

    

     for (int i = 0; i < 20; i+=3)

           v.push_back(i);

 

     auto result = find_if(begin(v), end(v),
                    
bind2nd(greater<int>(), 10
));

 

     cout << *result << endl;

 

     return 0;

}

 

TR1, now part of C++ 11, added the new bind method and the use of placeholders:

(I might write a future post about functional programing with TR1 (bind, placeholders, mem_fn))

 

#include "stdafx.h"

#include <algorithm>

#include <functional>

#include <iostream>

#include <vector>

 

using namespace std;

using namespace std::placeholders;

 

int _tmain(int argc, _TCHAR* argv[])

{

       vector<int> v;

      

       for (int i = 0; i < 20; i+=3)

              v.push_back(i);

 

       //auto result = find_if(begin(v), end(v), bind2nd(greater<int>(), 10));

       auto result = find_if(begin(v), end(v), bind(greater<int>(), _1, 10));

 

       cout << *result << endl;

 

       return 0;

}

 

However, using a Lambda function makes it much simpler; you actually do not need those functors anymore:

 

#include "stdafx.h"

#include <algorithm>

//#include <functional>

#include <iostream>

#include <vector>

 

using namespace std;

//using namespace std::placeholders;

 

int _tmain(int argc, _TCHAR* argv[])

{

       vector<int> v;

      

       for (int i = 0; i < 20; i+=3)

              v.push_back(i);

 

       //auto result = find_if(begin(v), end(v), bind2nd(greater<int>(), 10));

       //auto result = find_if(begin(v), end(v), bind(greater<int>(), _1, 10));

       auto result = find_if(begin(v), end(v),
                    
[](int value) { return value > 10; });

 

       cout << *result << endl;

 

       return 0;

}

 

So, what is a Lambda Function?

  • A construct that combines the benefits of function pointers and function objects
    • It’s an inline method (a closure)
  • With lambda you can:
    • Easily use any STL mechanism that needs a functor
    • Create array of functions
    • Use functional programming paradigm
      • Very useful for concurrent programming
    • Write shorter and readable code

 

Capture Variables

One of the main differences of using Lambda vs. using predefined functors is the ability of the lambda function to access, or capture, local variables of the enclosing function.

For example:

 

int v = 7, r = 8;

auto l = [v,&r](int i) 

     { 

           cout << v << ‘ ‘ << r << ‘ ‘ << i << endl;

     };

    

l(9);

 

The result is:

clip_image001[6]

 

The variable v is captured by value, i.e. the lambda uses a const copy of the value. The variable r is captured by reference, i.e. the lambda function refers to the same outer r variable memory location.

For example, this is a dangerous use of lambda:

function<void (int)> Foo()

{

       int v = 7, r = 8;

       auto l = [v,&r](int i) 

              { 

                     cout << v << ‘ ‘ << r << ‘ ‘ << i << endl;

              };

       return l;

}

int _tmain(int argc, _TCHAR* argv[])

{

      

       auto func = Foo();

      

       func(9);

 

 

       return 0;

}

 

The result is:

clip_image001[8]

 

In this case the r captured variable refers to a stack location that no longer exists.

Using the undocumented /d1reportAllClassLayout compiler switch, we can see that the compiler creates this class:

 

class <lambda0> size(16):

+—

0 | v

| <alignment member> (size=4)

8 | r

+—

 

The capturing syntax is:

clip_image002

 

Return Type:

Lambda can return nothing (void), or like any other function, it can return any value. If there is more than one return location in the lambda function body, you need to specify the return type using the trailing-return-type syntax:

clip_image004

 

Exceptions:

Like any other function, you can throw an exception from the lambda. Although exception specifications are deprecated, some compilers and tools still test exception correctness. You can also use exception specification syntax: []() throw () {}

 

Capture by value variable are constants

As we have seen, capture by value makes the captured variable into a const. This enables better code optimization. However sometime we want to change the captured copy in the lambda body:

int times = 10;

          

auto func = [times](const string &s)

{

     while (times > 0)

           cout << s << endl;

};

    

func("Alon");

 

This yields a compiler error:

error C3491: ‘times’: a by-value capture cannot be modified in a non-mutable lambda

To solve this, we can tell the compiler not to capture the variable as a const:

int times = 10;

          

auto func = [times](const string &s) mutable

{

     while (times > 0)

           cout << s << endl;

};

    

func("Alon");

 

Summary

Now you understand that [](){}(); is a call to a lambda function that captures nothing, takes nothing, returns void and does nothing.

Lambda is a very powerful mechanism. Using lambdas, your code will never look the same!

Read more about lambdas here

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*