- lambda表达式
一个lambda表达式具有如下形式:
[capture list](parameter list) -> return type [function body]
capture list(捕获列表):lambda所在函数中定义的局部变量的列表;
return type:返回类型
parameter list:参数列表
function body:函数体
//简例
auto f = [] { return 42 };
cout << f() << endl;//打印42
//如果忽略返回类型,lambda根据函数体中的代码推断出返回类型;
//如果函数体只是一个返回语句,则返回类型从返回的表达式的类型推断而来;
//否则,返回类型为void
- 一个容器操作和使用lambda表达式的例子
void elimDups(vector<string>& words)//对vector根据字典序重新排序,并且消除相同元素
{
sort(words.begin(), words.end());
auto end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());
}
bool isShorter(const string &s1, const string &s2)//谓词:用来比较string长度大小
{
return s1.size() < s2.size();
}
string make_plural(size_t ctr, const string& word, const string& ending)
{
return (ctr > 1) ? word + ending:word;
}
int main()
{
vector<string> fox;
fox.push_back("the");
fox.push_back("quick");
fox.push_back("red");
fox.push_back("fox");
fox.push_back("jumps");
fox.push_back("over");
fox.push_back("the");
fox.push_back("slow");
fox.push_back("red");
fox.push_back("turtle");
elimDups(fox);//字典序排序
sort(fox.begin(), fox.end(), isShorter);//size排序
for (auto iter = fox.begin(); iter != fox.end(); ++iter)
{
cout << *iter << endl;
}
//auto a = [](const string& a, const string& b) {return a.size() < b.size(); };//等同于isShorter
stable_sort(fox.begin(), fox.end(), isShorter);//size排序下对各个长度再进行字典序排序,isShorter可替换为a
for (const auto& s : fox)
cout << s << endl;
auto sz = 4;
auto wc = find_if(fox.begin(), fox.end(), [sz](const string& a) {return a.size() >= sz; });//找到第一个size>=sz的元素,返回该位置的迭代器
auto count = fox.end() - wc;//返回size>=sz的元素数目
cout << count << " " << make_plural(count, "word", "s") << " of length " << sz << " or longer " << endl;//输出size>=sz元素个数
for_each(wc, fox.end(), [](const string& s) {cout << s << " "; });//打印所有size>=sz的string,以空格分隔
//cout << *fox.end() << endl;
return 0;
}
- lambda捕获和返回
lambda表达式中捕获列表的内容是在lambda创建时拷贝,而不是调用时拷贝
void fcn1()
{
size_t v1 = 42;//局部变量
//将v1拷贝到名为f的可调用对象
auto f = [v1] { return v1; };
v1 = 0;
auto j = f();//j为42;f保存了我们创建它时的拷贝
}
void fcn2()
{
size_t v1 = 42;//局部变量
//对象f2包含v1的引用
auto f2 = [&v1} { return v1; };
v1 = 0;
auto j = f2();//j为0;f2保存v1的引用,而非拷贝
}
隐式捕获:为了指示编译器推断捕获列表,应在捕获列表中写一个&或=。&代表引用捕获方式,=代表值捕获方式。
//sz为隐式捕获,值捕获方式
wc = find_if(words.begin(),words.end(),[=](const string &s)
{ return s.size() >= sz; });
//一部分值捕获,一部分引用捕获
void biggies(vector<string> &words,vector<string>::size_type sz,
ostream &os = cout,char c = ' ')
{
//os隐式捕获,引用捕获方式;c显式捕获,值捕获方式
for_each(words.begin(),words.end(),[&,c](const string &s)
{os<<s<<c;};
//os显式捕获,引用捕获方式;c隐式捕获,值捕获方式
for_each(words.begin(),words.end(),[=,&os](const string &s)
{os<<s<<c;};
当我们混合使用隐式捕获和显式捕获时,捕获列表中的第一个元素必须是一个&或=。
当混合使用隐式捕获和显式捕获时,显式捕获的变量必须使用与隐式捕获不同的方式
- 可变lambda
如果我们希望能改变一个被捕获的变量的值,就必须在参数列表首加上关键字mutable
void fcn3()
{
size_t v1 = 42;//局部变量
//f可以改变他所捕获的变量的值
auto f = [v1] () mutable { return ++v1; };
v1 = 0;
auto j = f();//j为43
}
void fcn4()
{
size_t v1 = 42;
//v1是一个非const变量的引用
auto f2 = [&v1] { return ++v1; };
v1 = 0;
auto j = f2();//j为1
}
- 指定lambda返回类型
默认情况下,如果一个lambda体包含除return之外的任何语句,则编译器假定此lambda返回void。被推断返回void的lambda不能返回值。
//正确例子
transform(vi.begin(),vi.end(),vi.begin(),
[](int i) { return i<0 ? -i : i; };
//transform接受三个参数,前两个指定接受操作的序列,第三个为目的位置
//错误例子
transform(vi.begin(),vi.end(),vi.begin(),
[](int i) { if(i<0) return -i;else return i; };
//编译器会推断lambda返回void,但他返回了一个int值
当我们需要为一个lambda定义返回类型时,必须使用尾置返回类型
//正确例子
transform(vi.begin(),vi.end(),vi.begin(),
[](int i)->int { if(i<0) return -i;else return i; };