在c++11中,增加了不少的特性,才发现先的c++是如此的风骚
lambda
一个lambda表达式表示一个可调用的代码单元。我们可以将其理解为一个未命名的内联函数。与任何函数类似,一个lambda具有一个返回类型、一个参数列表、和一个函数体,但与函数不同,lambda可能定义在函数内部。一个lambda表达式具有如下形式
[capture list](parameter list)-> return type{function body}
- capture list(捕获列表)是一个lambda**所在函数定义局部变量**的列表(通常为空)
- return type:返回类型
- parameter list:参数列表
- function body:函数体
后面三个和普通函数一样,但是lambda必须使用尾置返回来指定类型,尾置返回简单说明在文章后面
* 我们可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体
* 在lambda中忽略括号和参数列表等价于指定一个空参数列表。
* 如果忽略返回类型,lambda根据函数体中的代码推断出返回类型,如只有一个return语句,则从返回表达式类型推断出来
* 如果lambda的函数体包含任何单一return语句之外的内容,且未指定返回类型,则返回void
忽略参数列表和返回类型的example
auto f = [] {return 42;};
cout << f() << endl;//打印42
// 注意是f()而不是f
向lambda传递参数
[](const string &a,const string &b)
{return a.size()<b.size();}
//使用
//按长度排序,长度相同的单词维持字典序
stable_sort(words.begin(),words.end(),
[](const string &a,const string &b)
{return a.size()<b,size();} );
空捕获列表表面此lambda不使用它所在函数中的任何局部变量。
使用捕获列表
一个lambda通过将局部遍历包含在其捕获列表中来指出将会使用这些变量,在这个例子中,lambda会捕获sz,并只有单一的string参数
[sz]{const string &a}
{return a.size()>=sz};
- 捕获列表只用于局部非static变量,lambda可以直接使用局部static变量和他所在函数之外声明的名字
完整的biggies
void biggies(vector<sting &words>,vector<string>::sizetype sz)
{
elimDups(words); //将word按字典序排毒,删除重复单词
//按长度排序,长度相同单词维持字典序
stable_sort(words.begin(),words.end(),
[](const string &a,const string &b)
{return a.size()<b,size();} );
//获取一个迭代器指向第一个满足size()>sz的元素
auto wc = find_if(words.begin(),words.end(),
[sz](const string &a)
{ return a,size()>=size; });
//计算满足size>=sz的元素的数目
auto count = words.end()-wc;
cout<<count<<" "<<make_pliral(count,"word",'s')<<" of length "<<sz<<" or longer"<<endl;
//打印长度大于等于给定值的单词,每个单词后面接一个空格
for_each(wc,words.end(),
[](const string &s){cout<<s<<" ";});
cout<<endl;
}
lambda捕获和返回
每个lambda表达式的类型是独一无二的。当向一个函数传递一个lambda时,同时定义了一个新类型和该类型的一个对象。
默认情况下,从lambda生成的类都包含一个对应 该lambda所捕获的变量的数据成员。
可以使用decltype关键字声明一个该类型成员
值捕获
被捕获的值是在lambda创建时拷贝,而不是调用时拷贝:
void fcn1()
{
size_t v1=42; //局部变量
//将v1拷贝到名为f的可调用对象
auto f = [v1]{return v1};
v1=0;
auto j = f(); //j为42,f保存了我们创建它时v1的拷贝
}
引用捕获
void fcn2()
{
size_t v1=42; //局部变量
//对象f2包含v1引用
auto f2 = [&v1]{return v1};
v1=0;
auto j = f2(); //j为0,f保存了v1的引用
}
如果必须采用引用方式捕获一个变量,必须保证被引用的对象在lambda执行的时候是存在的
隐式捕获
除了显示列出我们希望使用的来自所在函数的变量之外,还可以指示编译器根据lambda体中的代码来推断我们需要使用那些变量。
为了指示编译器推断捕获列表,应在捕获列表中写一个&或=。&告诉编译器采用捕获引用方式,=表示采用值捕获方式。
例如重写的find_if
//sz为隐式捕获,值捕获方式
wc = find_if(words.begin(),words.end,
[=](const string &s){return s.size()>=sz; });
如果希望对一部分变量采用值捕获,对其他变量采用引用捕获,可以混合使用隐式捕获和显示捕获,但捕获列表中的第一个元素必须是一个&或=
可变lambda
如果我们希望能改变一个被捕获的变量的值,就必须在参数列表首加上关键字mutable
void fcn3()
{
size_t v1 = 42;
//f可以改变它所捕获的变量的值
auto f=[v1]() mutable { return ++v1; };
v1=0;
auto j=f(); // j为43
}
尾置返回
一般来讲,尾置返回类型是为了使用decltype,或者纯粹让代码变得更可读。
decltype的例子如下,譬如说你可能不知道a+b到底返回什么类型:
template<typename T, typename U>
auto Add(T t, U u) -> decltype(t + u)
{
return t + u;
}
这样你不仅可以Add(1, 2),还可以Add(3.0, 4.0f),甚至还可以Add(“VczhIsAGenius”, 7)了。