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 }