zoukankan      html  css  js  c++  java
  • C++ 11 ----Lambda表达式

    Lambda表达式

     lambda介绍:

        一个lambda表达式表示一个可调用的代码单元。我们可以将其理解为一个未命名的内联函数。与任何函数类似,一个lambda具有一个返回类型、一个参数列表和一个函数体。但与函数不同,lambda可能定义在函数内部。一个lambda表达式具有如下形式:

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

        其中,capture list(捕获列表)是一个lambda所在函数中定义的局部变量的列表(通常为空);parameter list、return type和function body分为表示参数列表、返回类型和函数体。但是,与普通函数不同,lambda必须使用尾置返回来指定返回类型

        我们可以忽略参数列表和返回类型,但是必须永远包含捕获列表和函数体

        auto f = [] { return 42; };

        此例中,我们定义了一个可调用对象f,它不接受参数,返回42。

        lambda的调用方式与普通函数的调用方式相同,都是使用调用运算符:

        cout << f() << endl;   // 打印 42

        在lambda中忽略括号和参数列表等价于指定一个空参数列表。在此例中,当调用f时,参数列表是空的。如果忽略返回类型,lambda根据函数体中的代码推断出返回类型。如果函数体只是一个return语句,则返回类型从返回的表达式的类型推断而来。否则,返回类型为void

        Note:如果lambda的函数体包含任何单一return语句之外的内容,且未指定返回类型,则返回void。

     

    向lambda传递参数:

        与一个普通函数调用类似,调用一个lambda时给定的实参被用来初始化lambda的形参。通常,实参和形参的类型必须匹配。但与普通函数不同的是,lambda不能有默认参数。因此,一个lambda调用的实参数目永远与形参数目相等。一旦形参初始化完毕,就可以执行函数体了。

        作为一个带参数的lambda的例子,我们可以编写一个与isShorter函数完成相同功能的lambda:

        [](const string &a, const string &b) { return a.size() < b.size(); }

        空捕获列表表明此lambda不使用它所在函数中的任何局部变量。lambda的参数与isShorter的参数类似,是const string的引用。lambda的函数体也与isShorter类似,比较其两个参数的size(),并根据两者的相对大小返回一个布尔值。

        如下所示,可以使用此lambda来调用stable_sort:

        // 按长度排序,长度相同的单词维持字典顺序

        stable_sort(words.begin(),words.end(),

                    [](const strng &a,const string &b) { return a.size() < b.size(); });

        当stable_sort需要比较两个元素时,它就会调用给定的这个lambda表达式。

    使用捕获列表:

        我们现在已经准备好解决原来的问题了——编写一个可以传递给find_if的可调用表达式。我们希望这个表达式能够将输入序列中每个string的长度与biggies函数中的sz参数的值进行比较。

        虽然一个lambda可以出现在一个函数中,使用其局部变量,但它只能使用那些明确指明的变量。一个lambda通过将局部变量包含在其捕获列表中来指出将会使用这些变量。捕获列表指引lambda在其内部包含访问局部变量所需的信息。

        在本例中,我们的lambda会捕获sz,并只有单一的string参数。其函数体会将string的大小与捕获的sz的值进行比较:

        [](const string &a)

          { return a.size() >= sz;};

       lambda以一对[]开始,我们可以在其中提供一个以逗号分隔的名字列表,这些名字都是它所在函数中定义的

       由于lambda捕获sz,因此lambda的函数体可以使用sz。

       Note:一个lambda只有在其捕获列表中捕获一个它所在函数中的局部变量,才能在函数体中使用该变量。

     

    调用find_if :

        使用此lambda,我们可以查找第一个长度大于等于sz的元素:

        // 获取一个迭代器,指向第一个满足size() >= sz的元素

        auto wc = find_if(words.begin(),words.end(),

                         [sz](const string &a) { return a.size() >= sz; });

        这里对find_if的调用返回一个迭代器,指向第一个长度不小于给定参数sz的元素。如果这样的元素不存在,则返回words.end()的一个拷贝。

        我们可以使用find_if返回的迭代器来计算从它开始到words的末尾一共有多少个元素:

        // 计算满足size() >= sz的元素的数目

        auto count = words.end() - wc;

        cout << count << " " << make_plural(count,"word","s") << " of length " << sz << " or longre " << endl;

        我们的输出语句调用make_plural来输出“word”或“words”,具体输出哪个取决于大小是否等于1。

     

    for_each算法:

        问题的最后一部分是打印words中长度大于等于sz的元素。为了达到这一目的,我们可以使用for_each算法此算法接受一个可调用对象,并对输入序列中每个元素调用此对象:

        // 打印长度大于等于给定值的单词,每个单词后面接一个空格

        for_each(wc,words.end(),

                 [](const string &s) { cout << s << " ";});

        cout << endl;

    此lambda中的捕获列表为空,但是其函数体还是使用了两个名字:s和cout,前者是它自己的参数。

        捕获列表为空,是因为我们只对lambda所在的函数中定义的(非static)变量使用捕获列表。一个lambda可以直接使用定义在当前函数之外的名字。在本例中,cout不是定义在biggies中的局部名字,而是定义在头文件iostream中。因此,只要在biggies出现的作用域中包含了头文件iostream,我们的lambda就可以使用cout。

        Note:捕获列表只用于局部非static变量,lambda可以直接使用局部static变量和在它所在函数之外声明的名字。

     

    完整的biggies:

        到目前为止,我们已经解决了程序的所有细节,下面就是完整的程序:

     

     1 #include "stdafx.h"
     2 #include <iostream>
     3 #include <vector>
     4 #include <algorithm>
     5 #include <string>
     6 
     7 using namespace std;
     8 
     9 //比较函数,用来按长度排序
    10 bool isShorter(const string s1, const string s2)
    11 {
    12     return s1.size() < s2.size();
    13 }
    14 
    15 void elimDups(vector<string> &words)
    16 {
    17     // 按照字典排序words,以便查找重复单词(重复单词相邻出现)
    18     sort(words.begin(), words.end());
    19     // unique算法重排输入范围,使得每个单词只出现一次排列在范围的前部,
    20     // 返回指向不重复区域之后一个位置的迭代器。
    21     auto end_unique = unique(words.begin(), words.end());
    22     // 使用erase删除重复单词
    23     words.erase(end_unique, words.end());
    24 }
    25 
    26 string make_plural(size_t ctr, const string &word, const string &ending)
    27 {
    28     return (ctr > 1) ? word + ending : word;
    29 }
    30 
    31 void biggies(vector<string> &words, vector<string>::size_type sz)
    32 {
    33     elimDups(words);
    34     //按长度排序,长度相同的单词维持字典序
    35     stable_sort(words.begin(), words.end(),
    36                 [ ](string const & lhs, string const & rhs)
    37     {
    38         return lhs.size() < rhs.size();
    39     });
    40     //获取一个迭代器,指向第一个满足size()>= se的元素
    41     auto wc = find_if(words.begin(), words.end(),
    42                       [sz](const string & a)
    43     {
    44         return a.size() >= sz;
    45     });
    46     //计算满足size >= sz 的元素的数目
    47     auto count = words.end() - wc;
    48     cout << count << " " << make_plural(count, "word", "s")
    49          << " of length " << sz << " or longer " << endl;
    50     //打印长度大于等于给定值的单词,每个单词后面接一个空格
    51     for_each(wc, words.end(),
    52              [](const string & s)
    53     {
    54         cout << s << " ";
    55     });
    56     cout << endl;
    57 }
    58 
    59 int main()
    60 {
    61     cout << "Enter strings (Ctrl+z to end) : " << endl;
    62     string word;
    63     vector <string> words;
    64     while (cin >> word)
    65     {
    66         words.push_back(word);
    67     }
    68 
    69     //vector <string> words = { "the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red", "turtle" };
    70     vector <string> ::size_type sz = 5;
    71     biggies(words, sz);
    72     return 0;
    73 }

     

  • 相关阅读:
    CentOS 中安装和更新 git 客户端工具
    Python 快速入门笔记(2):数据类型
    Python 快速入门笔记(1):简介
    JavaScript快速入门笔记(15):Web storage 之 localStorage 和 sessionStorage
    JavaScript快速入门笔记(14):session
    JavaScript快速入门笔记(13):cookie
    JavaScript快速入门笔记(12):Ajax之XMLHttpRequest、jQuery、fetch()
    JavaScript快速入门笔记(11):事件处理
    python的线程和进程
    python中字符串编码转换
  • 原文地址:https://www.cnblogs.com/wyxsq/p/4936540.html
Copyright © 2011-2022 走看看