Using C++0x Lambda Expressions in Microsoft Visual Studio

Introduction

Many programming languages support the notion of an anonymous function--a function that has a body but doesn't have a name. An anonymous function is defined at the place of call and usually performs short computations. In earlier versions of C++ programming, the closest you could get to this was using a pointer to a function or a function object. Neither of these workarounds is ideal, though. Pointers to functions are stateless so they can't maintain values from previous calls. Function objects can maintain state but they require a full-blown class definition. The C++0x standard now supports a new feature called lambda expressions. A lambda expression is similar to an anonymous function. Its compact inline syntax removes the need for a manual class definition. Additionally, it can maintain state in C++ applications. Here I will show how to use C++0x lambda expressions in Visual C++ 10 (beta 2). Presently, several leading C++ compilers, including Intel C++ 11.0 and GCC 4.5, already support lambda expressions. Others are likely to follow suit soon.

The Pre-Lambda Era

Suppose you have a vector of integers. You want to check whether each integer in that vector is greater than a certain value. The canonical solution to such programming tasks uses the for_each algorithm to traverse the integers, and a function object that checks whether every integer is greater than a certain value. Here's an example of such a program that uses a function object:

<code>
//C++03 style
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int main()
{
  //Create a vector object, populate it with 10 integers
   vector<int> v;
   for (int i = 0; i < 10; ++i)
   {
      v.push_back(i);
   }
   //func is a function object. 5 is the cutoff value
   for_each(v.begin(), v.end(), func(5));
}</code>

This code looks compact until you look at the definition of class func:

<code>
class func
{
 int val; //Cutoff value, each int is compared against it
public:
 explicit func(int x): val(x) {}
 bool operator()(int n) {
  if (n>val)
  {
   cout << n <<" is greater than "<< val <<endl;
   return true;
  }
  else
   cout << n << " isn't greater than " << val <<endl;
  return false;
 }//operator()
};</code>

(The output from this program is shown in fig. 1)

The function object technique has two apparent shortcomings:

  1. You need to write the entire class on your own, including a constructor and an overloaded operator().
  2. You have no control over the usage of class func. Another programmer might misuse it or hack it (say by deriving from it).

Now let's see how the use of lambda expressions eliminates these problems.

Introducing Lambda Expressions in C++ Programming

Using the new lambda syntax, you can rewrite the previous for_each call like this:

<code>
int val = 5;
for_each(v.begin(), v.end(), [val] (int n)->bool {     
   if (n>val) //n contains the current vector element
   {
    cout<<n<<" is greater than "<<val<<endl;
    return true;
   }
   else
    cout<<n<<" isn't greater than "<<val<<endl;
   return false;
  });
</code>

The third argument of the for_each call begins with the token [val] and ends with the last } just before the closing parenthesis. The body of the lambda expression is identical to the body of the overloaded operator() defined in class func. Let's look at the lambda expression in greater detail.

All lambda expressions begin with the lambda introducer []. The introducer may be empty (this is known as a lambda with no external references), or it may contain identifiers from the enclosing scope, as shown in the example above. The latter is known as a lambda expression with external references, meaning the lambda accesses variables defined outside its parameter list.

The introducer and the identifiers within it are the capture clause of the lambda expression, (int n) specifies the parameter list, ->bool specifies the return type of the lambda expression, and the remaining part enclosed between {} is the body of the lambda expression. Your attention is drawn to the capture clause [val] because it has no equivalent in an ordinary function definition. A capture defines the environment, or a list of variables and objects that are declared in the lambda expression's enclosing scope. In the example above, the capture stores a local copy of val, allowing the lambda body to compare every integer in the vector against that value. You can think of the capture as the list of data members that you'd define in an equivalent function object. Later you will see how to pass the environment by reference.

In most cases, you don't have to specify the return type of the lambda expression. The compiler deduces it from the return statement in the body. However, when the body contains multiple return statements or when you want to make the return statement explicit you can specify the return statement after the lambda's parameter list like this:

 <code> 
[capture](parameters)->return-type {body} 
</code>

Pass By Reference

Sometimes you want the lambda expression to modify objects defined outside the lambda expression. For example, suppose you want to count how many uppercase letters a string has. The number of uppercase letters will be stored in a variable defined outside the lambda expression so that the program can access the result once the lambda expression has been evaluated. In the following code listing, for_each traverses a char array and uses a lambda expression with external references to check whether each letter is in uppercase. For every uppercase letter, the lambda expression increments the variable Uppercase:

 <code>
int main() 
{
   char s[]="Hello World!";

   int Uppercase = 0; //modified inside the lambda body
   for_each(s, s+sizeof(s), [&Uppercase] (char c) {     
    if (isupper(c))
     Uppercase++;
    });
 cout<< Uppercase<<" uppercase letters in: "<< s<<endl;
}
</code>

(see fig 2. for a screenshot of the complete code listing)

In the listing above, the capture [&Uppercase] contains an ampersand before the variable's name. This means that Uppercase is passed by reference, so that the lambda body can modify it.

The program scans every character in the string and reports whether it's an uppercase letter or not. The last line in the program displays the total number of uppercase letters. Here's the output from this program:

<code>
2 uppercase letters in: Hello World!
</code>

More on Lambdas

In the examples above I've shown how to pass the environment by value and by reference. There are additional capture forms that allow you to access the state of a class object from a lambda defined in a member function. I will discuss these advanced techniques in another article. In the meantime, take the time to digest this exciting new feature of C++0x. It's expected that lambda expressions will drastically reduce the use of function objects used in C++ applications, making your code more compact and easier to read and maintain.



Comments

  • Be prearranged you most fine higher-calibre in your be beguiled with

    Posted by rjjkwuia on 04/06/2013 06:48am

    Espy unequivocal simplified German skilful photographer [url=http://www.instylernewzealand.webs.com/]Instyler Hair[/url] Mario SuoLanrapture methodology watch invite assistance come by hold of lenses, from British supermodel Kate moss (Kate moss) to claim its advertising and marketing, melodic may be immortal devoted to liveliness, again from this summer's unmistakable bearer, to up on the at any rate be converted into be required to utensil, also [url=http://longchampssingapore.blogspot.com/]Longchamp Singapore[/url] acutely light-hearted typhoid mary, types and coloring perseverance winter font make-up be more dear, added a only just logo "dumplings pack", but in in to unfledged dough from a sizeable encapsulate倈the days of advanced in years|old-time hat} of [url=http://buylongchampsbag.blogspot.com/]Longchamp Bags[/url] layout.

    Reply
  • Purchase sale-priced products online since trading

    Posted by udlxqpmj on 04/01/2013 08:54am

    So varieties of [url=http://longchampsaustralia.webs.com/]Longchamp Bags[/url] these inveterately like announce all of the people. They may be capsule longchamp pas snow exceptionally vogue and luxuriant. In fabricate to earn rewards, you should pick, underneath, our products as a over payment more delicate and some other originate shopping and consequential appoint commitment be excellent. So most again won't exclude steam good delivery completed, if you hankering on [url=http://buylongchampsbag.webs.com/]Longchamp Australia[/url] to.

    Reply
  • useless academic exercise

    Posted by aao on 01/12/2011 10:13am

    so you took very simple/readable construct :
    int val = 5;
    for(v_type::iterator it = v.begin(), end = v.end(); it != end;++it)
    {     
       if (n>val) //n contains the current vector element
    	   cout<

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Learn How A Global Entertainment Company Saw a 448% ROI Every business today uses software to manage systems, deliver products, and empower employees to do their jobs. But software inevitably breaks, and when it does, businesses lose money -- in the form of dissatisfied customers, missed SLAs or lost productivity. PagerDuty, an operations performance platform, solves this problem by helping operations engineers and developers more effectively manage and resolve incidents across a company's global operations. …

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

Most Popular Programming Stories

More for Developers

RSS Feeds