C++11新特性——你所需要知道的关于匿名函数的一切
概述
在很多编程语言中,都存在着匿名函数,而C++也在11版本以后加入了这个新特性 顾名思义,匿名函数就是不用写函数名的函数,这要就解决了起函数名这个烦人的问题啦(当你只使用一次时) 接下来看看格式是怎样的
[ 捕获列表] ( 参数列表) -> 返回类型{ 函数体}
[ ] ( int a, int b) -> int { return a+ b; }
auto f= [ ] ( int a, int b) { return a+ b; } ;
我一开始并不理解,如果不给这个函数起名字的话,我该如何去调用它呢? 这里给出两种办法,一种是立刻调用,但以后再也不能调用了;另一种就是把这个函数当成一个变量,给它起一个名字。
int ans= [ ] ( int a, int b) -> int { return a+ b; } ( 10 , 54 ) ;
auto f= [ ] ( int a, int b) { return a+ b; } ;
f ( 10 , 90 ) ;
细心的朋友会发现,我在上面那个例子中有一个没有指定函数返回值,这是可以的,可以由编译器自动推断出类型 接下来,我们来说说mutable关键字和捕获列表
细说捕获列表
一开始我并不理解,为啥要有一个这么奇怪的东西存在 现在我大概了解了,是因为匿名函数往往都声明在一个函数内部,比如经常出现在main函数内部 此时,这个函数在main函数的作用域内,但如果不传入参数,则main函数中的其余变量该匿名函数都是访问不到的 其实我认为捕获列表就是一个参数列表,只不过在使用上可以更加方便,例如你要使用很多本地变量,你不需要一个个去传参 下面举一个例子
int main ( )
{
int t= 10 ;
auto f= [ ] ( ) { cout<< "t=" << t<< endl; } ;
f ( ) ;
return 0 ;
}
而假如你在参数列表中加入了这个变量,函数内部就可以访问到了,就像下面这样
int main ( )
{
int t= 10 ;
auto f= [ t] ( ) { cout<< "t=" << t<< endl; } ;
f ( ) ;
return 0 ;
}
接下来,我们来思考这个t的值在函数内部会不会改变呢? 我们来做个实验
int main ( )
{
int t= 10 ;
auto f= [ t] ( ) { cout<< "t=" << t++ << endl; } ;
f ( ) ;
return 0 ;
}
这样是会报错的,编译器会说表达式必须是一个可以修改的左值 那你肯定就会想,如果想修改,可不可以传指针或者引用呢? 答案是:可以滴!!
int main ( )
{
int t= 10 ;
auto f= [ & t] ( ) { cout<< "t+1=" << ++ t<< endl; } ;
f ( ) ;
cout<< "t=" << t<< endl;
return 0 ;
}
但是,目前不支持指针传递 你现在也许会说,这和参数列表有啥区别,接下来,我们来看看这个捕获列表到底可以写点啥
捕获形式 说明 [] 不捕获任何外部变量 [变量名,…] 默认以值的形式捕获制定的外部变量(逗号分割) [this] 以值的形式捕获this指针 [=] 以值的形式捕获所有外部变量 [&] 以引用的形式捕获所有外部变量 [&, a] 以值的形式捕获外部变量a,以引用的形式捕获其他外部变量 [=, &a] 以引用的形式捕获外部变量a,以值的形式捕获其他外部变量
细说mutable关键字
你肯定会问,哪来的mutable关键字?那是因为我还没有给出匿名函数的完整表达形式
[ capture_list] ( params_list) mutable exception-> return type { function_body}
学过c++面向对象的同学们应该知道,在一个类中,可以声明一个常函数,常函数不可以修改成员变量,除非这个成员变量使用了mutable关键字来修饰(我都快忘光了) 同样的,匿名函数也是一个常函数,他默认是不可以修改捕获列表中变量的值的,除非在这个匿名函数参数列表后面加上mutable关键字 这里,我们仅针对捕获列表为值传递的情况 注意,mutable关键字可以省略,如果要写,则必须写()来代表参数列表,哪怕是无参函数
int main ( )
{
int t= 10 ;
auto f= [ t] ( ) mutable {
t+= 10 ;
cout<< "t=" << t<< endl; } ;
f ( ) ;
f ( ) ;
cout<< "t=" << t<< endl;
return 0 ;
}
我们可以看到,mutable生效了,我们可以修改t的值了 且细心的人会发现,这并不影响匿名函数外面t的值 且在函数内部,这个t的值就像被static关键字修饰了一样,这个变量的生命周期变得像main函数一样了