什么是C++11中的lambda表达式?

什么是C++11中的lambda表达式?我什么时候用?在引入之前,他们解决了哪类问题是不可能的

一些示例和用例将非常有用

问题

C++包含有用的通用函数,如std::for_eachstd::transform,非常方便。不幸的是,它们的使用也非常麻烦,特别是如果您要应用的函子对于特定函数是唯一的

#包括<算法>
#包括<向量>
名称空间{
结构f{
void运算符()(int){
//做点什么
}
};
}
void func(标准::向量<int>&v){
f;
标准::对于每一个(v.begin(),v.end(),f);
}

如果您只在特定的地方使用f一次,那么编写一个完整的类只是为了做一些琐碎的事情,而且是一次性的,这似乎有些过分

在C++03中,您可能会尝试编写以下内容,以保持函子的局部性:

无效函数2(标准::向量<int>&v){
结构{
void运算符()(int){
//做点什么
}
}f;
标准::对于每一个(v.begin(),v.end(),f);
}

但是,这是不允许的,f不能传递给C++03中的模板函数

新的解决方案

C++11引入了lambda,它允许您编写一个内联匿名函子来替换结构f。对于小的简单示例,它可以更清晰地阅读(它将所有内容保存在一个位置),并且可能更易于维护,例如以最简单的形式:

void func3(标准::向量<int>&v){
std::for_each(v.begin(),v.end(),[](int){/*在这里做点什么*/});
}

Lambda函数只是匿名函子的语法糖

返回类型

在简单情况下,会为您推导lambda的返回类型,例如:

无效函数4(标准::向量<双>&v){
std::transform(v.begin(),v.end(),v.begin(),
[](双d){返回d<0.00001?0:d;}
);
}

但是,当您开始编写更复杂的lambda时,会很快遇到编译器无法推断返回类型的情况,例如:

无效函数4(标准::向量<双>&v){
std::transform(v.begin(),v.end(),v.begin(),
[](双d){
如果(d<0.0001){
返回0;
}否则{
返回d;
}
});
}

要解决此问题,您可以使用->显式指定lambda函数的返回类型;T

无效函数4(标准::向量<双>&v){
std::transform(v.begin(),v.end(),v.begin(),
[](双d)->双d{
如果(d<0.0001){
返回0;
}否则{
返回d;
}
});
}

&引用;捕捉;变数

到目前为止,除了在lambda中传递给lambda的内容之外,我们没有使用任何其他内容,但是我们也可以在lambda中使用其他变量。如果要访问其他变量,可以使用capture子句(表达式的[]),该子句在这些示例中尚未使用,例如:

无效函数5(标准::向量<双精度>&v,常数双精度&epsilon){
std::transform(v.begin(),v.end(),v.begin(),
[ε](双d)->双{
if(d<ε){
返回0;
}否则{
返回d;
}
});
}

您可以通过引用和值进行捕获,您可以使用&amp和=分别为:

  • [&epsilon]通过引用捕获
  • [&]通过引用捕获lambda中使用的所有变量
  • [=]按值捕获lambda中使用的所有变量
  • [&,epsilon]捕获像[&]这样的变量,但epsilon是按值捕获的
  • [=,&epsilon]捕获类似[=]的变量,但epsilon通过引用

默认情况下,生成的operator()const,这意味着当您默认访问它们时,捕获将是const。这样做的效果是,具有相同输入的每个调用都将产生相同的结果,但是您可以将lambda标记为可变,以请求生成的运算符()不是常量

发表评论