博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++ 11 ----Lambda表达式
阅读量:4988 次
发布时间:2019-06-12

本文共 4663 字,大约阅读时间需要 15 分钟。

 

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 
3 #include
4 #include
5 #include
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
&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
&words, vector
::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
words;64 while (cin >> word)65 {66 words.push_back(word);67 }68 69 //vector
words = { "the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red", "turtle" };70 vector
::size_type sz = 5;71 biggies(words, sz);72 return 0;73 }

 

转载于:https://www.cnblogs.com/wyxsq/p/4936540.html

你可能感兴趣的文章
OC--init,initialize,initWithCoder:,initWithFrame:各方法的区别和加载顺序
查看>>
Exponentiation
查看>>
本地jar上传到本地仓库
查看>>
四则运算C++带Qt界面版本,吾王镇楼。。。。。
查看>>
安卓7.0手机拍照闪退问题解决
查看>>
ME525+ Defy+ 刷机指南[zz]
查看>>
支持触屏的jQuery轮播图插件
查看>>
差一点搞混了Transactional注解
查看>>
javascript基本函数
查看>>
前端公共库cdn服务推荐//提高加载速度/节省流量
查看>>
snprintf 返回值陷阱 重新封装
查看>>
asp.net GridView多行表头的实现,合并表头
查看>>
C#套打
查看>>
PolyCluster: Minimum Fragment Disagreement Clustering for Polyploid Phasing 多聚类:用于多倍体的最小碎片不一致聚类...
查看>>
【每日进步】July 2012
查看>>
327 作业
查看>>
sql 取汉字首字母
查看>>
bzoj4034: [HAOI2015]树上操作(树剖)
查看>>
${sessionScope.user}的使用方法
查看>>
WCF开发框架形成之旅---结合代码生成工具实现快速开发
查看>>