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.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read