lambda表达式
一个lambda表达式表示一个可调用代码单元,可以理解为一个未命名的内联函数。
[capture list](parameter list) -> return type { function body }
其中,我们可以忽略参数列表和返回类型,但必须包括捕获列表和函数体,
例如:auto f = [ ] { return 42; };
完整的biggies函数实现(含大量注释):
/*从vector<string> words中数出长度大于等于sz的单词,并打印每个单词*/
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
//是否返回复数形式
std::string make_plural(size_t ctr, const std::string& word, const std::string& ending);
//字典序,并删除重复单词
void elimDups(std::vector<std::string>& words);
void biggies(std::vector<std::string>& words,
std::vector<std::string>::size_type sz) {
elimDups(words);
//按长度排序,长度相同的单词维持字典序
stable_sort(words.begin(), words.end(),
[](const std::string& a, const std::string& b) { return a.size() < b.size(); });
//获取一个迭代器,指向第一个满足size()>=sz的元素
auto wc = find_if(words.begin(), words.end(),
[sz](const std::string& a) {
return a.size() >= sz;
}); //捕获列表捕获函数内的局部变量
//计算满足size>=sz的元素数目
auto count = words.end() - wc;
//输出多少个
std::cout << count << " " << make_plural(count, "word", "s")
<< " of length " << sz << " or longer. " << std::endl;
//输出每个单词
for_each(wc, words.end(),
[](const std::string& s) {std::cout << s << " "; });
std::cout << std::endl;
}
std::string make_plural(size_t ctr, const std::string& word, //size_t类型表示任何对象所能达到的最大长度,它是无符号整数,方便系统之间的移植,不同系统的size_t的定义可能不同
const std::string& ending) { //size_t在32位系统上定义为 unsigned int,也就是32位无符号整型。在64位系统上定义为 unsigned long ,也就是64位无符号整形。
return (ctr > 1) ? word + ending : word;
}
void elimDups(std::vector<std::string>& words) {
//字典序
sort(words.begin(), words.end());
//unique重排输入范围,使得每个单词只出现一次,不重复区域排在范围前面,返回指向不重复区域之后一个位置的迭代器
auto end_unique = unique(words.begin(), words.end());
//使用向量操作erase删除单词
words.erase(end_unique, words.end());
}
理解lambda的定义和传递
-
当定义一个lambda时,编译器生成一个与lambda对应的新的没有命名的类类型;
-
当向函数传递一个lambda时,同时定义了一个新类型和该类型的一个对象:传递的参数就是这个没有命名的对象,这个类包含一个对应捕获的变量的数据成员。
lambda捕获变量的方式
- 值捕获,[v1],在lambda被创建的时候拷贝该变量;
- 引用捕获,[&v1],须保证该局部变量在lambda执行时存在,
还要注意所指向的对象从创建lambda到执行是否发生改变 ; - 隐式捕获,[&]、[=],根据lambda体内代码确定要捕获的变量,其中的符号告诉编译器采用哪种捕获方式。
一般来说,我们应该尽量减少捕获的数据量,来避免潜在的捕获导致的问题。可能的话,应该避免捕获指针和引用。
- 另外,如果想要修改捕获的变量,值捕获需要加上mutable,引用捕获依赖于变量本身是否是const类型:auto f = [v1] () mutable { return ++v1; };
lambda的返回类型
- 必须使用尾置返回来指定返回类型;
//尾置返回类型
auto func() -> int(*)[10]; //在原本的出现返回类型的地方放置auto,返回一个指向含有10个整数数组的指针
- 如果lambda的函数体只包含单句return语句,可以忽略返回类型,编译器会通过return内容推断返回类型;
- 如果lambda的函数体包含单句return语句之外的内容,且没有指定返回类型,则返回void。