Lambda expression / function

Lambda expressions are unnamed objects that overload unnamed classes of function call operators ().
A Lambda expression can be considered an anonymous function object.
Like any function, a Lambda expression contains a return type, a parameter list, and a function body.

Lambda definition

[captuer_list](parameter_list) -> return_type { function_body }
  • captuer_list is a capture list, which is a list of local variables defined in the function where the Lambda expression is located
  • return_type is a trailing return, which is the return type of a Lambda expression. If you want to explicitly declare the type of the return value, you must use this form
  • Lambda expressions must contain capture lists and function bodies.

Pass arguments to Lambda expressions

By default, classes generated from Lambda expressions contain a data member corresponding to the variable captured by the Lambda expression.

Similar to the data members of any ordinary class, the data members of Lambda expressions are also initialized when Lambda expression objects are created, that is, the captured variable values are copied when Lambda expressions are created, not when they are called.

void func() {
    int n = 10;
    auto func = [n]() { return n; };    // n is copied into the Lambda expression when it is created
    n = 0;                              // Changing external values does not affect the copy in Lambda
    auto m = func();                    // When called, the value of the copy of n in the Lambda expression is 10
    cout << m << endl;				    // 10
}

The number of arguments of Lambda expression cannot be equal by default.

Lambda's capture method

grammar explain
[] Empty capture list. Lambda cannot use a variable in its function
[names] Names is a list of names separated by, which are local variables of the function where the Lambda expression is located. By default, all variables in the capture list are copies
[&] The implicit capture list adopts the reference capture method. All entities from the function used in Lambda expressions are referenced
[=] Implicit capture list, using value capture method. The entities from the function used in Lambda expression are passed by value
[&, identifier_list] identifier_list] is a separated list containing 0 or more variables from the function, and these variables are captured by value, while any implicitly captured variables are captured by reference_ List] cannot be used before the name&
[=, identifier_list] identifier_list] is a, separated list containing 0 or more variables from the function, and these variables are captured by reference, while any implicitly captured variables are captured by reference_ Names in list] cannot contain this and must be used before these names&
  • Implicit capture is to let the compiler infer the variables that may be used according to the code in the Lambda body.

  • When implicit capture and explicit capture are mixed, the first element in the capture list must be & or =, which specifies the type of default capture method.

  • When implicit capture and explicit capture are mixed, explicitly captured variables must be captured in a different way from implicit capture.

    // Capture example
    void func() {
        int n = 10;
        // Value capture
        auto func1 = [n]() { return n; };
        // Reference capture
        auto func2 = [&n]() { return n; };
    
        n = 0;
        auto p = func1();		            // p = 10
        auto q = func2();		            // q = 0
    }
    

Variable Lambda

  • By default, Lambda does not change the value of a variable whose value is copied.
    If we want to change the value of a captured variable, we must add the keyword mutable at the beginning of the parameter list, and the variable Lambda can omit the parameter list.

    void func() {
        int n = 10;
        auto func1 = [n]() { return ++n; };             // error: replication capture cannot be modified in a non mutable lambda
        auto func2 = [n]() mutable { return ++n; };     // ok
    }
    
  • Whether the variable captured by the reference can be modified depends on whether the reference points to a const or a non const type.

    void func() {
        int n = 10;
        const int m = 81;
        auto func1 = [&n]() { return ++n; };	
        auto func2 = [&m]() { return ++m; };            // error: replication capture cannot be modified in a non mutable lambda
        auto func3 = [&m]() mutable { return ++m; };    // error: lvalue specifies const object
    }
    

Specify Lambda return type

By default, if a Lambda body contains any statement other than return, the compiler assumes that the Lambda body returns void
When you need to define a return type for Lambda, you must use the trailing return type.

int n = -10;
auto func1 = [](int i) { return i > 0 ? i : -i; };	
auto func2 = [](int i) { if (i > 0) return i; else return -i; };
auto func3 = [](int i) -> decltype(i) { if (i > 0) return i; else return -i; };

Tags: C++

Posted by gardner1 on Thu, 14 Apr 2022 15:34:46 +0930