Topic: Programming/C++.

3rd story:What’s a lambda? A deep look into lambdas.

The lambda function, introduced in C++11 and further enhanced with polymorphic capabilities in C++14, is one of the most useful features in modern C++. Its versatility comes not only from easily passing functions to algorithms but it can also be used in a lot of circumstances where you need to pass the code around, especially as you can store a lambda function in std::function.

Although the lambda function made these programming techniques vastly simpler to work with, everything here is possible to perform without them by making classes with operator() overloaded.

We will explore the lambda function’s similarities to these kind of classes later, but first let’s introduce the lambda function in a simple use case.

Basic syntax of a lambda:

The lambda function capability enables programmers to pass functions to regular functions, just as easily as a variable is passed.

std::vector<int>values{1,2,4,5,7};

auto greater_than_3 = [](int v){ return v > 3; };

auto num_above_3 = std::count_if(values.begin(), values.end(), greater_than_3);

This is a typical use case for lambda functions, we pass a function to be evaluated many times to another function (in this case, std::count_if).

The capture bloc:

Let’s make this a little more advanced. In the previous example, we hard coded the value we wanted to count numbers above. What if we want to use an external variable inside the lambda instead? What we do is capture the external variables by putting them in the capture block, that is, the [] part of the lambda:

auto count_value_above(const std::vector<int>& values, int val) {

auto is_above = [val](int v) { return v > th; }; return std::count_if(values.begin(), values.end(), is_above);

}

Conversion to a Function Pointer:

If your lambda doesn’t capture then:

The closure type for a lambda-expression with no lambda capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

Let’s say you are using a C library, or an older C++ library, which uses a callback function as a parameter. For convenience, you would like to use a lambda function like this: external void download_webpage(const char* url, void (*callback)(int, const char*));

The callback here is a return code and the web page HTML. If you want to invoke this with a lambda, you have to use a plus in front of the lambda in order to convert it into a regular function pointer:

auto func() {

auto lambda = +[](int result, const char* str) {};

download_webpage(“http://www.linux.org”, lambda);

}

Mutating lambda member variables:

As the lambda function works just like a class with member variables, it can also mutate them. In the following example, the lambda mutates the threshold variable every time it is invoked. In order to allow the lambda to mutate its members, we need to specify mutable when declaring the lambda. The mutable modifier on a lambda function works like the inverse for a const modifier for a regular class member function; in contrast to a class member function, a lambda function is const by default, and therefore a mutating lambda must be explicitly specified:

Capture by value

Capture by reference

Similarities between a Lambda and a class:

To understand what the lambda function consists of, one can view it as a regular class with restrictions:

The class only consists of one member function.

The capture block is a combination of the class’s member variables and its constructor.

Each lambda function has its own unique type. Even if two lambda functions are plain clones of each other, they still have their own unique type.

C++ | STL | Semiconductors | VHDL | SoCs | FPGAs | Python | Visual Studio | sometimes Go