Fork me on Github Fork me on Gitee

C++温故补缺(二):lambda函数

Lambda函数

参考:CSDN

C++11开始,提供了对匿名函数的支持,成为Lambda函数(表达式)

通常,lambda函数用于封装传递给算法或异步方法的几行代码,对应不需要复用,且短小的函数,使用lambda函数可以增加代码的可读性

格式:

auto function=[capture list](parameters) mutable throw()->return-type {statement}

一般用一个auto变量来接收,然后通过这个变量名function(paramenters)调用,也可以直接附上参数,不需要auto变量名

[capture list](paramenters) mutable throw()->return-type {statement}(real paramenters)

例如:

auto function=[a,&b](int x) mutable ->int {return a+b+x;};
int m=function(20);
//another
int m=[a,&b](int x) mutable ->int {return a+b+x;}(20);
  • 捕获列表:在C++规范中也称Lambda导入器,[]就是lambda引出符,编译器根据该引出符判断接下来的代码是否lambda函数,捕捉列表能捕捉上下文中的变量,供Lambda函数使用,也就相当于在函数中调用函数外的变量.
  • 参数列表:和普通函数的参数列表一致,如果不需要传递参数,则可以连同()一同省略
  • 可变规格:mutable修饰符,默认情况下lambda函数总是一个const函数,mutable可以取消其常量性,如果使用了mutable,则参数列表不可省略
  • 异常说明:用来抛出异常
  • 返回类型:声明函数的返回类型,如果不需要返回值,则可以连同符号->一起省略,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推到
    • int a; return a+2;编译器就能自动推导返回值类型为int
  • lambda函数体:和普通函数别无二致,除了传入的参数,还可以使用捕获的变量

捕获列表

捕获列表就是lambda以值传递或引用传递的方式调用上下文的变量

  • []表示不捕获任何变量
auto function=[]{std::cout<<"Hello";};
function();

这是一个简单的lambda例子,它的功能是输出"hello"

  • [var]表示值传递的方式捕获变量var
int num=100;
auto function=[num]{std::cout<<num;};
function();

捕获就是在lambda表达式内部调用外面的变量,值传递相当于普通函数的值传递形式

  • [=]表示值传递方式捕获父作用域的所有变量,包括this
int a=100;
float b=1.2;
auto function=[]{cout<<a<<endl<<b;};
function();
  • [&var]表示引用传递捕捉变量var
int a=100;
auto function=[]{a++;cout<<a;};
function();

也就是能在lambda表达式中改变变量的值

  • [&]表示引用传递捕捉父作用域的所有变量
int a=100;
float b=1.2;
auto fnction=[]{a++;
                b+=2.3;
                cout<<a<<endl<<b;};
function();
  • [this]表示值传递方式捕捉当前的this指针
#include<iostream>
using namespace std;

class test{
    public:
        void sayHello(){
            cout<<"hello"<<endl;
        }
        void lambda(){
            auto function=[this]{this->sayHello();};
            function();
        }
};
int main(){
    test t1;
    t1.lambda();
}
  • [=,&]拷贝和引用混合

    • [=,&a,&b]:以值传递的方式捕捉其他所有变量,以引用方式捕捉a,b

    • [&,a,this]:以值传递捕捉a和this,其他用引用方式

  • 捕捉列表不允许变量重复传递,如

    • [=,a]:已经捕捉了所有变量,重复捕捉a,会报错

    • [&,&this]:也是会报错

参数列表

格式和使用都和普通函数无二致

auto function=[](int x,int y){return x+y};
int a=function(100,200);

可变规格mutable

通过值传递方式捕获的变量在lambda中默认是const类型,只能输出,不能改变,使用mutable可以使其可变,但是只能在lambda中短暂使用,并不能影响到父作用域的变量

int a=1;
auto function=[a]() mutable {a++;};
function();

这时参数列表()不能省略,可以使空的参数列表,但()不能省

lambda的优缺点

优点:

  • 可以直接在需要调用函数的位置定义短小精简的函数,不需要预先定义好函数

  • 可以使代码结构更紧凑,因为调用的函数的定义就在旁边,不用向前后向后找,可读性更好

缺点:

  • 增加了阅读代码的难度

  • 无法复用

工作原理

编译器会把一个Lambda表达式生成一个匿名类的匿名对象,并在类中重载函数调用运算符,实现了一个operator()方法

auto print=[]{cout<<"hello"<<endl;};

编译器会把它翻译为下面的代码:

class print_class{
    public:
        void operator()(void) const{
            cout<<"hello"<<endl;
        }
};
auto print=print_class();
posted @ 2023-03-20 23:17  Tenerome  阅读(67)  评论(0编辑  收藏  举报