目录
1.概念和基本用法
1.1. 基本语法
Lambda表达式定义一个匿名函数,并可以捕获一定范围内的变量。
语法形式如下:
[capture](params) opt ->ret {body;}
//@ capture–捕获列表
//@ params–参数列表
//@ opt–函数选项
//@ ret–返回值类型
//@ body–函数体
示例:
auto f = [] (int a) -> int { return a+1;}
std::cout << f(1) << std::endl;//输出2
auto f1 = [] {return 1;}
Lambda表达式是通过返回值后置语法]定义的。
Lambda表达式没有参数列表时,参数列表是可以省略的,如上第三行写法是正确的。
1.2. 捕获列表释义
捕获列表捕获一定范围内的变量:
- [] 不捕获任何变量;
- [&] 捕获外部作用域中所有变量,并作为引用在函数体中使用–按引用捕获;
- [=] 捕获外部作用域中所有变量,并作为副本在函数体中使用–按值捕获;
- [=,&foo] 按值捕获外部作用域所有变量,并按引用捕获foo变量;
- [bar] 按值捕获bar变量,不捕获其它变量;
- [this] 捕获当前类中的this指针,让Lambda表达式拥有和当前类成员函数同样的访问权限。捕获this的目的是可以在Lambda中使用当前类的成员函数和成员变量。
如下代码便于更好理解。
例一:
class A
{
public:
int i=0;
void FuncTest(int x,int y)
{
auto x1 = [] { return i; };//error,没有捕获到外部变量i,会提示"i 未声明的标识符"
auto x2 = [=] { return (i+x+y); };//OK,捕获所有变量
auto x3 = [&] {return (i+x+y);};//OK,捕获所有变量
auto x4 = [this] {return i;};//OK,捕获类A的this指针
auto x5 = [this] {return (i+x+y);};//error,捕获this指针是为了使用当前类的成员函数和成员变量,会提示错误,无法捕获x,y
auto x6 = [this,x,y] {return i+x+y;};//OK,捕获类A的this指针和x,y
auto x7 = [this] {return i++;};//OK,捕获this指针,并修改成员变量
}
};
例二:
int m = 0,n = 1;
auto f1 = [] {return m;}; //error,没有捕获外部变量,会提示错误:无法隐式捕获m,因为未指定默认捕获模式
auto f2 = [&] {return m++;}; //OK,捕获外部所有变量,并对m进行自加运算
auto f3 = [=] {return m;}; //OK,捕获外部变量,并返回m
auto f4 = [=] {return m++;}; //error,m是以按值的方式捕获的,没有办法修改,会提示错误:m 无法在非可变lambda中修改通过复制捕获
auto f5 = [m] {return m+n;}; //error,并没有捕获n,会提示错误:无法隐式捕获n
auto f6 = [m,&n] {return m+(n++);}; //OK,m按值方式捕获,n按引用捕获,可以自加
auto f7 = [=,&n] {return m+(n++);}; //OK,捕获外部所有变量和n的引用,对n做自加运算
以上可以看出来lambda表达式的捕获列表控制lambda表达式能够访问的外部变量,以及如何访问这些变量。
默认状态下lambda表达式无法修改通过复制方式捕获的外部变量,如果要修改这些变量的话,需要使用引用方式进行捕获。
如果希望修改按值捕获的外部变量,需要显示指明lambda表达式为mutable,即:
int a=0;
auto f1 = [=] {return a++;}; //error
auto f2 = [=] () mutable {return a++;}; //ok,mutable修饰的lambda表达式就算没有参数也要写明参数列表.
1.3. lambda表达式的类型
lambda表达式的类型在C++11中被称为”闭包类型”,是一个特殊的,匿名的非nunion的类类型。
可以使用*std::function*和*std::bind*来存储和操作lambda表达式。
std::function<int(int)> f1 = [](int a) { return a;};
std::function<int(void)> f2 = std::bind( [] (int a) {return a;},123};
另外,对于**没有捕获任何变量**的lambda表达式,还可以被转换成一个普通的函数指针:
using func_t = int(*) (int);
func_t f = [] (int a) { return a;};
f(123);
按照C++标准,lambda表达式的operator()默认是const的,mutable作用就是取消operator()的const。
2.使用
示例一:调用for_each函数将vector中的偶数打印出来
使用lambda表达式之前:
class CountEvent
{
int& m_cout;
public:
CountEvent(int& count)
:m_cout(count)
{
}
void operator() (int val)
{
if(!(val & 1))
{
++m_cout;
}
}
};
vector<int> v = {1,2,3,4,5,6};
int event_count = 0;
for_each(v.begin(),v.end(),CountEvent(event_count));
cout << "the numbers of even is " << event_count << endl;
使用lambda表达式,用闭包概念替换到仿函数operator(),如下:
vector<int> v = {1,2,3,4,5,6};
int event_count = 0;
for_each(v.begin(),v.end(),[&event_count] (int val)
{
if(!(val&1))
++event_count;
});
cout << "the numbers of even is " << event_count << endl;
这两种写法效果是一样的,都可以求出最终的结果,可以看出使用lambda表达式之后代码很简洁清晰。
lambda表达式的价值在于,就地封装短小的功能闭包,可以极其方便的表达出我们希望执行的操作。
参考书籍:《深入应用C++11 代码优化与工程级应用》–祁宇
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/46140.html