• C++学习:lambda表达式入门


    引言:lambda表达式在STL应用中可以让我们起到十分便捷的功能,我们看下微软的解释。

    When you write code, you probably use function pointers and function objects to solve problems and perform calculations, especially when you use STL algorithms. Function pointers and function objects have advantages and disadvantages—for example, function pointers have minimal syntactic overhead but do not retain state within a scope, and function objects can maintain state but require the syntactic overhead of a class definition.

    A lambda combines the benefits of function pointers and function objects and avoids their disadvantages. Like a function objects, a lambda is flexible and can maintain state, but unlike a function object, its compact syntax doesn't require a class definition. By using lambdas, you can write code that's less cumbersome and less prone to errors than the code for an equivalent function obj。

    当我们写代码的时候,可以使用函数指针或者函数对象去解决问题和计算,尤其在使用STL的内置算法时,不过函数指针都有明显的优劣势,举个例子,函数指针有简洁的语法但是(不包含状态一定范围内),函数对象是包含状态,但是需要专门去定义一个类并重载函数调用操作符。

    This illustration maps the grammar to an example:

    Structural elements of a lambda expression

    1. lambda-introducer (Also known as the capture clause)&捕获全部  &para 捕获特定参数 =copy

    2. lambda declarator (Also known as the parameter list)输入参数

    3. mutable (Also known as the mutable specification) 是否可以修改 const属性的参数

    4. exception-specification (Also known as the exception specification) 异常

    5. trailing-return-type (Also known as the return type) 返回值类型

    6. compound-statement (Also known as the lambda body) 函数体

    下面引入两个例子,看一下lambda表达式带来的好处,两个的demo实现的是相同的功能;

    1.利用函数对象实现,必须要定义一个类并重载call-function符号

     1 // even_functor.cpp
     2 // compile with: /EHsc
     3 #include <algorithm>
     4 #include <iostream>
     5 #include <vector>
     6 using namespace std;
     7 
     8 class FunctorClass
     9 {
    10 public:
    11     // The required constructor for this example.
    12     explicit FunctorClass(int& evenCount)
    13         : m_evenCount(evenCount) { }
    14 
    15     // The function-call operator prints whether the number is
    16     // even or odd. If the number is even, this method updates
    17     // the counter.
    18     void operator()(int n) const {
    19         cout << n;
    20 
    21         if (n % 2 == 0) {
    22             cout << " is even " << endl;
    23             ++m_evenCount;
    24         } else {
    25             cout << " is odd " << endl;
    26         }
    27     }
    28 
    29 private:
    30     // Default assignment operator to silence warning C4512.
    31     FunctorClass& operator=(const FunctorClass&);
    32 
    33     int& m_evenCount; // the number of even variables in the vector.
    34 };
    35 
    36 
    37 int main()
    38 {
    39     // Create a vector object that contains 10 elements.
    40     vector<int> v;
    41     for (int i = 1; i < 10; ++i) {
    42         v.push_back(i);
    43     }
    44 
    45     // Count the number of even numbers in the vector by 
    46     // using the for_each function and a function object.
    47     int evenCount = 0;
    48     for_each(v.begin(), v.end(), FunctorClass(evenCount));
    49 
    50     // Print the count of even numbers to the console.
    51     cout << "There are " << evenCount
    52         << " even numbers in the vector." << endl;
    53 }

    输出:
    1 is odd 2 is even 3 is odd 4 is even 5 is odd 6 is even 7 is odd 8 is even 9 is odd There are 4 even numbers in the vector

    看看简洁的lambda表达式如何实现同样的功能。
     1 // even_lambda.cpp
     2 // compile with: cl /EHsc /nologo /W4 /MTd
     3 #include <algorithm>
     4 #include <iostream>
     5 #include <vector>
     6 using namespace std;
     7 
     8 int main() 
     9 {
    10    // Create a vector object that contains 10 elements.
    11    vector<int> v;
    12    for (int i = 1; i < 10; ++i) {
    13       v.push_back(i);
    14    }
    15 
    16    // Count the number of even numbers in the vector by 
    17    // using the for_each function and a lambda.
    18    int evenCount = 0;
    19    for_each(v.begin(), v.end(), [&evenCount] (int n) {
    20       cout << n;
    21       if (n % 2 == 0) {
    22          cout << " is even " << endl;
    23          ++evenCount;
    24       } else {
    25          cout << " is odd " << endl;
    26       }
    27    });
    28 
    29    // Print the count of even numbers to the console.
    30    cout << "There are " << evenCount 
    31         << " even numbers in the vector." << endl;
    32 }

    Output:

    1 is odd
    2 is even
    3 is odd
    4 is even
    5 is odd
    6 is even
    7 is odd
    8 is even
    9 is odd
    There are 4 even numbers in the vector.

    Summery:
    看得出lambda表达式代码的好处十分的明显,使代码变得简洁,语义变的清晰。代码不易膨胀,出bug的概率也变小了。下面我们介绍下lambda最基本的语法

    Caputre的规则
    struct S { void f(int i); };
    
    void S::f(int i) {
        [&, i]{};    // OK
        [&, &i]{};   // ERROR: i preceded by & when & is the default
        [=, this]{}; // ERROR: this when = is the default
        [i, i]{};    // ERROR: i repeated
    }

    上下文的capurue要注意一些规则, [&]是获取全部reference而不是单个变量的reference, [&para]才是获取单个变量的reference,

    =同理,只不过是上下文全部以copy的方式进行传递。

    lambda :body的规则

    // captures_lambda_expression.cpp
    // compile with: /W4 /EHsc 
    #include <iostream>
    using namespace std;
    
    int main()
    {
       int m = 0;
       int n = 0;
       [&, n] (int a) mutable { m = ++n + a; }(4);
       cout << m << endl << n << endl;
    }

    lambda表达式的body中可以包含方法或者函数,而这些函数是可以访问lambda所captrue的变量的。

     The body of both an ordinary function and a lambda expression can access these kinds of variables:

    • Parameters

    • Locally-declared variables

    • Class data members, when declared inside a class and this is captured

    • Any variable that has static storage duration—for example, global variables

    以上4中变量都是可以访问的。

    In addition, a lambda expression can access variables that it captures from the enclosing scope. A variable is explicitly captured if it appears in the capture clause of the lambda expression. Otherwise, the variable is implicitly captured. The body of the lambda expression uses the default capture mode to access variables that are implicitly captured.

    The following example contains a lambda expression that explicitly captures the variable n by value and implicitly captures the variable m by reference:


    值得注意的是,lambda表达式可以访问不同的变量从captures,一个变量可以显式的从捕获中获取,或者通过隐式捕获,body中可以使用默认的捕获方式去访问隐式捕获的变量

    下面这个例子就是看到显式的捕获n,和隐式的捕获m的引用。
     1 // captures_lambda_expression.cpp
     2 // compile with: /W4 /EHsc 
     3 #include <iostream>
     4 using namespace std;
     5 
     6 int main()
     7 {
     8    int m = 0;
     9    int n = 0;
    10    [&, n] (int a) mutable { m = ++n + a; }(4);
    11    cout << m << endl << n << endl;
    12 }

    Output:

    5
    0



    更多详情请看 https://msdn.microsoft.com/en-us/library/dd293603.aspx
  • 相关阅读:
    【从0安装】安装pycharm
    【从0安装】安装appium
    【从0安装】安装android sdk
    【从0安装】安装java jdk
    【从0安装】安装nodejs
    【技术解析】如何用Docker实现SequoiaDB集群的快速部署
    巨杉数据库助力民生银行、广发银行前台智慧化业务
    巨杉数据库入选Gartner数据库报告,中国首家入选厂商
    【操作教程】利用YCSB测试巨杉数据库性能
    巨杉数据库首批入选广州数字金融协会,引领大湾区数字金融创新
  • 原文地址:https://www.cnblogs.com/DLzhang/p/4645978.html
Copyright © 2020-2023  润新知