Home  >  Article  >  Backend Development  >  A brief analysis of Lambda expressions, new features of C++11

A brief analysis of Lambda expressions, new features of C++11

高洛峰
高洛峰Original
2017-01-23 13:44:161544browse

Introduction to lambda

Programmers familiar with Python should be familiar with lambda. Simply put, a lambda is an anonymous callable block of code. In the new C++11 standard, lambda has the following format:

[capture list] (parameter list) -> return type { function body }

As you can see, it has four components:

1.capture list: Capture List

2.parameter list:Parameter list

3.return type:Return type

4.function body:Execution code

Among them, the parameter list and return type can be ignored.

Below, let’s look at a few simple examples:

auto f1 = [] { return 1; };
auto f2 = [] () { return 2; };
cout<<f1()<<&#39;\t&#39;<<f2()<<endl;

Capture list

The capture list in lambda can capture both values ​​and Quote.

Capture value:

int test_data[] = {1, 5, 9, 7, 3, 19, 13, 17};
int border = 8;
auto f3 = [border](const int &i){ if(i > border) cout<<i<<&#39;\t&#39;; };
for_each(begin(test_data), end(test_data), f3);
cout<<endl;

Capture reference:

auto f4 = [&border](const int &i){ if(i > border) cout<<i<<&#39;\t&#39;; };
border = 6;
for_each(begin(test_data), end(test_data), f4);
cout<<endl;

As can be seen from the output, the border that works in lambda It is the modified 6, confirming that the capture is indeed a reference.

It should be noted that when capturing a reference, you need to ensure that this reference is still valid when the lambda is called.

The capture list can also use implicit capture, which allows the compiler to determine which local variables need to be captured through the lambda execution code.

Implicit capture can capture values, references, or a mixture of the two:

char space = &#39; &#39;;
auto f5 = [=](const int &i){ if(i > border) cout<<i<<&#39;\t&#39;; };
auto f6 = [&](const int &i){ if(i > border) cout<<i<<&#39;\t&#39;; };
auto f7 = [&, space](const int &i){ if(i > border) cout<<i<<space; };
border = 0;
for_each(begin(test_data), end(test_data), f5);
cout<<endl;
for_each(begin(test_data), end(test_data), f6);
cout<<endl;
for_each(begin(test_data), end(test_data), f7);
cout<<endl;

The mixed form used by f7 here can be read as "in addition to space capture values" , other variables capture references".

Variable lambda

When the lambda needs to modify the value of the variable captured by the value, the mutable keyword needs to be added to the lambda. Otherwise there will be compilation errors.

auto f8 = [&, space](const int &i) mutable { if(i > border) {cout<<i<<space; space=&#39;\t&#39;;} };
for_each(begin(test_data), end(test_data), f8);
cout<<endl;
cout<<1<<space<<2<<endl;

As can be seen from the output, the value of space in lambda f8, after the first call, was turned into the tab character Tab; but outside the lambda , space is still a space.

Return type

The return type of lambda adopts the tail return type method. General:

1. If the lambda only contains a return statement, the compiler can infer its return type, and the return type does not need to be specified explicitly;

2. Otherwise, compile The compiler assumes that lambda returns void, and a function that returns void cannot return any specific value. This is a contradiction in most cases, so the return type needs to be explicitly specified.

However, after actual testing, the current g++ compiler is smarter: for point 2, currently as long as the compiler can infer the return type of the function from the lambda function body, there is no need to explicitly Formula to specify the return type, for example:

auto f9 = [](const int i){if(i % 3) return i * 3; else return i;};
transform(begin(test_data), end(test_data), begin(test_data), f9);
border = 0;
for_each(begin(test_data), end(test_data), f6);
cout<<endl;

There are multiple return statements in the lambda code block, and there are also if/else statements, but the compiler can infer based on the return statement that its return The value should be of type int, so the trailing return type can be omitted.

However, in the following form, since the compiler finds inconsistencies when inferring the return type, the return type must be explicitly specified:

auto f10 = [](const int i) -> double
{if(i % 5) return i * 5.0; else return i;};
transform(begin(test_data), end(test_data), begin(test_data), f10);
for_each(begin(test_data), end(test_data), f6);
cout<<endl;

Summary

1. Lambda expression form: [capture list] (parameter list) -> return type { function body }, where parameter list and return type can be omitted.

2. The capture list can capture the value [val] or the reference [&ref].

3. The capture list can also implicitly capture local variables. There are also two methods of capturing value [=] and capturing reference [&]. In addition to the first time, you can also mix capture [&, val] Or [=, &ref].

4. When lambda needs to modify the captured value, the mutable keyword needs to be added.

4. When lambda cannot automatically infer the return value type, it needs to be specified explicitly by appending the return type.

The above is the entire content of the Lambda expression, a new feature of C++11. I hope this article will be helpful to everyone learning C++.

For more articles related to Lambda expressions that briefly analyze the new features of C++11, please pay attention to the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn