C++ Lambda expression

1. Basic grammar

[Capture list](Parameter list) mutable(optional) Exception attribute -> return type { // function body }

Syntax rules: lambda expressions can be regarded as general functions whose function names are omitted, and the return value is expressed in the form of a ->. The only difference from ordinary functions is the addition of a "capture list".

Second, understand the capture list

The so-called capture list can actually be understood as a type of parameter. By default, the internal function body of a lambda expression cannot use variables outside the function body. At this time, the capture list can serve to transfer external data . According to the behavior of passing parameters, the capture list
can be divided into the following types:

1. Value capture

Similar to parameter passing by value, the premise of value capture is that the variable can be copied. The difference is that the captured variable is copied when the lambda expression is created , rather than when it is called:

void lambda_value_capture() {
    int value = 1;

    auto copy_value = [value] {
        return value;
    };

    value = 100;
    auto stored_value = copy_value();
    std::cout << "stored_value = " << stored_value << std::endl;
    // 这时, stored_value == 1, 而 value == 100.
    // 因为 copy_value 在创建时就保存了一份 value 的拷贝
}

2. Reference capture

Similar to passing parameters by reference, reference capture saves the reference , and the value will change.

void lambda_reference_capture() {
    int value = 1;

    auto copy_value = [&value] {
        return value;
    };

    value = 100;
    auto stored_value = copy_value();
    std::cout << "stored_value = " << stored_value << std::endl;
    // 这时, stored_value == 100, value == 100.
    // 因为 copy_value 保存的是引用
}

3. Implicit capture
Manually writing a capture list is sometimes very complicated. This mechanical work can be handled by the compiler. At this time, you can write an & or = in the capture list to declare to the compiler that capture by reference or Value capture.

void lambda_reference_capture() {
    int value = 1;

    auto copy_value = [&] {
        return value;
    };

    value = 100;
    auto stored_value = copy_value();
    std::cout << "stored_value = " << stored_value << std::endl;
    // 这时, stored_value == 100, value == 100.
    // 因为 copy_value 保存的是引用
}

4. Empty capture list

The capture list'[]' is empty, which means that Lambda cannot use the variable in the function.

#include <iostream>

int main()
{
	int c = 12;
	auto Add = [](int a, int b)->int {
		return c;  // 编译失败,c没有被捕获
	};

	std::cout << Add(1, 2) << std::endl;

	return 0;
}

5. Expression capture

The value capture and reference capture mentioned above are variables that have been declared in the outer scope, so these capture methods capture lvalues, not rvalues .

After C++14, it supports capturing rvalues, allowing captured members to be initialized with arbitrary expressions. The type of the declared captured variable will be judged according to the expression. The judgment method is essentially the same as using auto:

#include <iostream>
#include <utility>

int main() 
{
    auto important = std::make_unique<int>(1);

    auto add = [v1 = 1, v2 = std::move(important)](int x, int y) -> int {
        return x + y + v1 + (*v2);
    };

    std::cout << add(3,4) << std::endl;

    return 0;
}

In the above code, important is a unique_ptr exclusive pointer, which cannot be captured. At this time, we need to transfer it to an rvalue and initialize it in the expression.


6. Generic Lambda

Before C++14, the formal parameters represented by lambdas could only specify specific types and could not be generic. The exciting thing is that starting from C++14, the formal parameters of Lambda functions can use the auto keyword to generate generics in the sense:

auto add = [](auto x, auto y) {
    return x+y;
};

add(1, 2);
add(1.1, 2.2);

Three, summary

Capture provides the function of using external values ​​in lambda expressions. The four most commonly used forms of capture lists can be:
• [] empty capture list
• [name1, name2,...] To capture a series of variables
• [&] Quotation capture, let the compiler derive the capture list by itself
• [=] Value capture, let the compiler execute the deduction reference list

Capture list syntax table presentation:

Capture list Explanation
[] Empty capture list. lambdaThe variables in the function cannot be used. One lambdacan only use them after the variables are captured.
[names] namesIt is a comma-separated list of names. These names are all lambdalocal variables in the function where they are located. The variables in the capture list are all copied. If used before the name &, the reference capture method is used.
[&] The implicit capture list is captured by reference. lambdaEntities from the function used in the body are all used by reference.
[=] Implicit capture list, using value capture method.
[&, identifier_list] identifier_listIs a comma-separated list containing 0 or more variables from the function in which it is located. These variables are captured by value, and any implicitly captured variables are captured by reference. identifier_listCannot be used in front of the name in&
[=, identifier_list] identifier_listThe variables in are captured by reference, and any implicitly captured variables are captured by value. identifier_listThe name in cannot be included this, and must be used before&

[Note] Many of the above contents are from "Modern C++ Tutorial", which are excerpted and expanded here, and should be used as study notes.

Guess you like

Origin blog.csdn.net/xunye_dream/article/details/109701333