原书P345
目录
介绍lambda
我们可以向算法(这里的算法指标准库中实现的可调用的一些接口)传递任何类别的调用对象。
对于一个对象或一个表达式,如果可以对其使用调用运算符,则称它为可调用的。即,如果e是一个可调用的表达式,则我们可以编写代码e(args),其中args是一个逗号分隔的一个或多个参数的列表。
lambda表达式格式
一个lambda表达式表示一个可调用的代码单元。我们可以将其理解为一个未命名的内联函数。与任何函数类似,一个lambda具有一个返回类型,一个参数列表和一个函数题。但与函数不同,lambda可能定义在函数内部,一个lambda表达式具有如下形式:
[capture list](parameter list)->return type{function body}
其中,capture list是一个lambda所在函数中定义的局部变量的列表,其余的和普通函数一样。
lambda中忽略括号和参数列表等价于指定一个空参数列表。
如果忽略返回类型,lambda根据函数体中的代码推断出返回类型。
举个栗子:
![](https://img-blog.csdnimg.cn/0f5d7ea0614a4dc98c18121fafdaa224.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHNnb29zZQ==,size_19,color_FFFFFF,t_70,g_se,x_16)
lambda捕获和返回
当定义一个lambda时,编译器生成一个与lambda对应的新的类类型。可以这样理解,当向一个函数传递lambda时,同时定义了一个新类型和该类型的一个对象:传递的参数就是此编译器生成的类类型的未命名对象。类似的,当使用auto定义一个lambda初始化的变量时,定义了一个从lambda生成的类型的对象。
值捕获
类似参数传递,变量的捕获方式可以是值或引用:
引用捕获
隐式捕获
除了显式列出我们希望使用的来自所在函数的变量之外,还可以让编译器根据lambda中的代码来推断我们要使用哪些变量。=表示值捕获,&表示引用捕获:
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=' ')
{
for_each(words.begin(),word.end()
[&,c](const string &s){os<<s<<c;});
for_each(words.begin(),word.end()
[=,&os](const string &s){os<<s<<c;});
}
捕获列表的一些规则如下表所示:
可变lambda
参数绑定
对于那种只在一两个地方使用的简单操作,lambda表达式是最有用的。如果我们需要在很多地方使用相同的操作,通常应该定义一个函数,而不是多次编写相同的lambda表达式。类似的,如果一个操作需要很多语句才能完成,通常使用函数更好。
如果lambda的捕获列表为空,通常可以用函数来代替它。
但是,对于捕获局部变量的lambda,用函数来替换它就不是那么容易了。例如我们用在find_if调用中的lambda比较一个string和一个给定大小。我们可以很容易地编写一个完成同样工作的函数:
bool check_size(const string &s,string::size_type sz)
{
return s.size()>=sz;
}
但是,我们不能用这个函数作为find_if的一个参数。如前文所示,find_if接受一个一元谓词,因此传递给find_if的可调用对象必须接受单一参数,biggies传递给find_if的lambda使用捕获列表来保存iz。为了用check_size来代替此lambda,必须解决如何向sz形参传递一个参数的问题。
标准库bind函数
bind函数的格式如下:
auto newCallable=bind(callable,arg_list)
可以将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来适应原对象的参数列表。
arg_list中的参数可能包含形如_n的名字,其中n是一个整数。这些参数是“占位符”,表示newCallable的参数,它们占据了传递给newCallable的参数的位置。
关于这个参数列表在书中的例子:
不过注意_1,_2等占位符是放在std::placeholders里边的,为了方便可以用using