C++11新增的匿名函数 Lambda表达式,其格式如下:
[capture捕获列表](参数列表)->返回类型{函数体}其中capture捕获列表用于获取其所在scope的上下文变量。
关于捕获capture:
通过[=] :
Lambda表达式所在块scope的上下文变量以传值方式全部捕获。
int a=3; int main() { int a=1; int b=2; auto fun=[=](){return a+b;}; //捕获所在scope的a cout<<fun()<<endl; }输出:
若将a移到所在scope不可见,那么将无法通过编译:
int main() { { int a=1; } int b=2; auto fun=[=](){return a+b;}; cout<<fun()<<endl; }编译不通过:
通过[&] :
Lambda表达式所在块scope的上下文变量以引用方式全部捕获。
int main() { int a=2; int b=2; auto fun=[&](){a+=b;}; fun(); cout<<"a: "<<a<<endl; }输出a的值被改变:
通过[&a,b] :
Lambda表达式将捕获指定的变量,以传值或引用方式:
int main() { int a=2; int b=2; auto fun=[&a,b](){a+=b;}; //以引用方式捕获a 传值方式捕获b fun(); cout<<"a: "<<a<<endl; }注意,捕获的变量是Lambda函数目前的上下文环境,其不能捕获之后的变量。
int a=2; auto fun=[=]()->int{return a+b;};//将报错 显示b未声明 int b=2;另外,Lambda传值方式捕获之后,外界变量的修改不会影响结果。
int main() { int a=2; int b=2; auto fun=[=]()->int{return a+b;}; cout<<fun()<<endl; //输出2+2=4 b=3; //修改b cout<<fun()<<endl;//实际仍然输出2+2=4 }输出:
即:
匿名函数捕获scope上下文环境变量时,只会捕获一次,可以认为被捕获变量初始化了匿名函数,之后不再改变。
参数列表和函数类似,特别地,若不带参数,那么可以省略:
auto fun=[=]{return a+b;}; //除捕获变量外 没有外界调用参数另外,通常可以不指定返回值类型(编译器自动推导),也可以指定
int main() { float a=2.5; float b=2.6; auto fun=[=]()->int{return a+b;}; //会作一个float=>int的转换 cout<<fun()<<endl; }输出:
【匿名函数与函数指针】:
auto fun=[=]()->int{return a+b;}; //Lambda表达式类型并不是函数指针很容易想到Lambda表达式可能是函数指针,但其实不是简单的函数指针类型,其是一种闭包类型。
函数指针是函数入口地址,而函数通常逻辑是:传递参数=》执行函数=》返回值
而Lambda表达式,除了常规参数外,还有捕获列表变量参与函数执行。
当Lambda表达式没有捕获变量时,可以转化为函数指针。
int main() { auto fun=[](int a,int b)->int{return a+b;};//捕获列表为空 int (*p)(int,int)=fun;//转化为函数指针 cout<<p(1,2)<<endl; }
由于Lambda函数相比较于一般函数多了捕获列表变量。
因此禁止: 函数指针=》Lambda函数
为什么不建议使用函数指针? ①函数指针定义通常在别处,未知其定义情况下阅读使用困难。 ②函数指针必然带来函数调用的开销,不能使用inline技术优化
【匿名函数与inline函数】:
宏定义:
在预编译阶段简单的将源代码使用宏的部分作展开,只作文本替换,并不进行语法检查,使用不当容易造成错误。
inline函数:
将逻辑简单,代码简单的函数定义为inline 那么编译器在编译时将直接在所有调用处直接展开代码逻辑。避免函数调用带来的开销。同时相对于宏定义,其能进行语法检查,符合函数定义的规范。
inline函数的优缺点如下:
编译器在调用处作展开,避免函数调用带来的开销。相比较与宏定义,有完整的语法检查,类型检查。由于每个调用处都会在编译期展开,会造成代码复杂度增加,空间占用增大。程序实际加载进内存时,若大量使用inline函数,必然造成代码区内存占用增大。因此,编译器会作一个判断,当inline修饰的函数代码足够短时才作展开。
Lambda匿名函数默认是 static inline 即:
static表明其只在本作用域scope范围内可见。inline表明其编译时会在调用处作展开,避免过程调用的开销。