lambda表达式:适用于只需要在少数地方使用
[函数的局部变量](参数列表)->返回类型{}
- 类似于无名的inline函数
- 必须包含函数的局部变量和函数体(即使为空)
例如
auto f=[]{ return 42; }
cout<<f()<<endl;
- 如果在未指定未返回类型的情况下,函数包含return语句之外的内容则返回类型为void
- 必须使用尾置返回来设置返回类型。
[](int i)->int{if(i<0)return -i;else return i;}
- 不能有默认参数
- 尽量减少捕获指针/引用
- 适当使用 lambda 表达式。别用默认 lambda 捕获,所有捕获都要显式写出来。
匿名函数始终要简短,如果函数体超过了五行,那么还不如起名(acgtyrant 注:即把 lambda 表达式赋值给对象),或改用函数。 如果可读性更好,就显式写出 lambd 的尾置返回类型,就像auto.
示例:
将isShorter函数改为lambda表达式
[]{const string &s1,const string &s2}
{ return s1.size()<s2.size(); }
并令其被stable_sort函数调用
stable_sort( words.begin(),words.end(),
[]{const string &s1,const string &s2}
{ return s1.size()<s2.size(); } );
显式捕获:
- []只用于局部的非static变量,lambda表达式可以直接使用局部static变量和函数之外声明的名字。
- []值捕获的变量是在lambda表达式创建时拷贝(函数参数是在调用时拷贝)
auto f=[v1]{ return v1; };
//lambda默认不会改变被捕获的值。只能通过mutable改变
auto f=[v1]()mutable{ return ++v1; };
通过lamada产生的类需要利用值捕获的变量创建构造函数,来初始化数据成员。
例如
[sz](const string &a){ return a.size()>=sz; }
相当于产生
- 和重载了函数调用运算符的类相比,多了构造函数和私有成员。
- 该类不包含默认构造/析构函数和赋值运算符
- 根据捕获的数据类型决定是否包含默认的拷贝/移动构造函数
class SizeComp{
SizeComp(size_t n):sz(n){}
bool operator()(const string &s)const
{ return a.size()>=sz; }
private:
szie_t sz;
};
//调用时
find_if(words.begin(),words.end(),SizeComp(sz) );
- []引用的对象需要保证在lambda执行时存在。
auto f=[&v1]{ return v1; };
//根据引用是否为const决定能否修改捕获的对象
- 隐式捕获
[=]{参数列表}->返回类型{}
[&]{参数列表}->返回类型{}
当混合使用显式捕获和隐式捕获时
- 第1个元素必须是隐式捕获
- 显式捕获和隐式捕获的方式必须不同
对于不需要捕获局部变量的lambda可以直接由函数替代。
对于有局部变量的可以使用bind函数
auto 新可调用对象=bind(可调用对象,逗号分隔的参数列表);
当调用新可调用对象时,新可调用对象会调用并将参数传递给bind函数中的可调用对象。
参数列表可能包含占位符(_n):
- 表示传递给新可调用对象参数的第n个参数。
- 由于_n都位于命名空间placeholders中,而且对于每个占位符都要提供单独的声明。
using std::placeholders::_1;
//为了方便:
using namespace std::placeholders;
示例:
bool check_size(const string &s,string::size_type sz);
auto check6=bind(check_size,_1,6);
//_1对应check_size的第1个参数
//6对应sz
调用时
string s="hello";
bool b1=check6(s);
//相当于调用check_size(s,6)
注意在bind函数中非占位符的参数将会被拷贝到返回的可调用对象中,由于bind函数无法直接使用引用,对于无法进行拷贝的对象使用ref函数/cref函数返回引用。
ref(os)
可以使用bind函数重排参数的顺序
sort( words.begin() , words.end() , bind(isShorter,_2,_1) );