C++11:Lambda匿名函数

    科技2022-07-21  94

    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表明其编译时会在调用处作展开,避免过程调用的开销。

     

     

     

     

     

     

    Processed: 0.011, SQL: 8