C++11: Let’s Write a “Hello Lambda!”

A lambda expression (aka lambda function), introduced in C++11 standard, is a simplified notation for defining an anonymous function object. However, its syntax and using may look weird for many people so let’s try to make a simple program to accommodate with it.

// Example #1

#include <iostream>

int main()
{
    [] () mutable throw() ->void { std::cout << "Hello Lambda!"; } ();
}

Let’s describe each part, in order.

The parts of a lambda expression

  • [] is the lambda introducer that may be empty or may contain a capture list; this part is mandatory for defining a lambda expression;
  • () is a formal parameters list; if it takes no parameters and no specifier like mutable or noexcept has been used, this part is optional;
  • mutable is an optional specifier which indicates that the copies of variables captured by value can be modified inside the lambda body;
  • throw() (or noexcept) is an exception specifier which is also optional;
  • ->void is the return type; it is optional if the compiler can deduce the return type;
  • { std::cout << "Hello Lambda!"; } is the body specifying the code to be executed.
  • finally, we have in our example a function-call operator, (), which is not a part of lambda expression.

Getting rid of optional parts, we can make our program simpler, as follows:

// Example #2

#include <iostream>

int main()
{
    [] { std::cout << "Hello Lambda!"; } ();
}

Further, let’s take a little deeper look in the lambda introducer part.

The lambda introducer and the capture list

As already said before, the lambda introducer that may be empty or may contain a capture list. An empty lambda introducer means “no capture is made”. Otherwise, the local variables from the place where lambda is defined can be “captured” (i.e. used in the lambda body) as follows:

  • [=] all local variables are implicitly accessed by value;
  • [&] all local variables are implicitly accessed by reference;
  • [capture_list] a list of variable names to be captured (explicit capture); if a variable name is preceded by & then it is captured by reference; otherwise, it is captured by value;
  • [=, capture_list] all variables which are not in the capture_list are captured by value;
  • [&, capture_list] all variables which are not in the capture_list are captured by reference;

Note that variables captured by value cannot be modified inside the lambda body, except case the mutable specifier has been used.
Now, let’s make our program a little bit more complicated to illustrate the using of capture list and other lambda expression parts.

// Example #3

#include <iostream>
#include <string>
#include <functional>
#include <ctime>

void say_hello(std::function<bool(int)> lambda_func, unsigned int max_count)
{
    for (unsigned int index = 0; index < max_count; index++)
    {
        // call back lambda function until returns false
        if (false == lambda_func(index))
        {
            std::cout << "stopped due 'false' returned" << std::endl;
            break;
        }
    }
}
int main()
{
    srand(static_cast<unsigned int>(time(NULL)));

    std::string hello = "Hello";
    std::string lambda = "Lambda";

    const unsigned int max_count = 100;

    // pass lambda function to say_hello;
    say_hello(
        // 'hello' local variable is captured by value
        // 'lambda' local variable is captured by reference
        // the parameter list contains a parameter of type unsigned int
        // the return type is bool
        [hello, &lambda](unsigned int print_index) ->bool
    {   // lambda body begin
        lambda += "!"; // the variable 'lambda' is captured by reference
                       // so can be modified inside lambda body
        std::cout << hello << " " << lambda
            << " print #" << print_index << std::endl;
        // randomly return 'false' to stop 
        return (rand() % 5) ? true : false;
    },  // lambda body end
        max_count);

    return 0;
}

Notes

  • This article presented just trivial examples, introducing lambda expressions as simple as possible. You can find tens of articles and examples presenting lambdas deeper. See also references and related articles, below.
  • std::function is an STL class that wraps callable objects like functions, lambda expressions and so on.

References and related articles

Leave a Comment