c++学习笔记之【lambda表达式】

lambda表达式:

lambda是c++在c++11中引入的新特性,作为一个语法糖,lambda在c++11、c++14、c++17、c++20以及即将推出的c++23中都有更新。

lambda函数与普通函数的区别

lambda函数与普通函数的区别在于,除了使用参数表之外,lambda函数可以通过捕获列表来访问上下文的数据,在捕获列表中,捕获列表规定了上下文的哪些数据和变量是可以被我们使用的,以什么方式被使用的。语法上,lambda函数的是以*[]开头的,[]*里面的内容就是一个捕获列表。捕获列表可以由多个捕获项组成,多个捕获项之间以,隔开。接下来说说lambda的语法。

捕获列表:

[ ]表示不捕获任何变量

由于捕获列表中为空,此处我们告诉编译器说这个lambda函数不需要捕获上下文中的任何元素。

[var]表示以值传递的方式捕获变量var

其中的var是代替任意的变量名,假如存在一个变量为a,那么[a]的意思就是以值传递的方式将a传入lambda表达式中。值得一提的是,以这个方式传入lambda函数中的值是一个副本,且是const的,如果想要解除lambda表达式中的这一属性,那么就必须在后面参数表的下一个位置加上mutable声明。以下是一段示例的代码。

#include <bits/stdc++.h>
using namespace std;
int main(){
int a=100;
  auto f1=[a](){return a+=100;
  f1();//报错,此处的a是一个const变量,我们不能改变a的值};
  auto f2=[a](){return a+100;
  f2();//正确,此时函数的返回值为200};
  cout<<f2();//结果为200;
  return 0;   
}
[&var]表示传入var的引用,

与上面相同的是,var代表的是任意的变量名,但与以值传递的方式传入函数不同的是,&var传入的是函数的引用,也即是说,你在lambda函数里边对这个变量做出的操作是会改变原值的,而且传入的值是无需加mutable修饰也可以进行修改的。

以下是一段的示例的代码:

#include <bits/stdc++.h>
using namespace std;
int main(){
int a=100;
cout<<a<<endl;//此时打印结果为100
auto f=[&a](){
 a*=20;
};
f();//此时a的值变为2000;
cout<<a;//此时打印结果为2000;


}
[=]表示以值传递捕获父作用域内所有变量(包括this指针):

也即是说,当捕获列表为‘=’时,可以捕获当前作用域内的所有变量,包括this指针,可以通过this指针访问父类中的成员函数,但由于是值传递的方式传入的,所以如果想要修改传入的值的话,需要添加mutable修饰。

以下是一段代码示例;

#include <bits/stdc++.h>
using namespace std;
int main(){
int a=0,b=100,c=300;
auto f1=[=](){return a+c+b;};//合法
auto f2=[=]()mutable{
  c*=b;
  a+=c;
return a;};//合法 mutable解除了值传递进函数的const属性。
/*
auto f3=[=]{c*=b;
a+=c;
return a;};*/ //违法的,值传递进去的变量是const属性的,不能改变。
  cout<<f1()<<" "<<f2(); //将f3注释后可以运行 打印结果为400 30000
  return 0;
}
[&]表示以引用的方式捕获父作用域内的所有变量(包括this指针)

与用引用方式捕获变量类似,[&]的意思是捕获父作用域内的所有内的所有变量,并以引用的方式传入lambda函数,也就是说修改lambda函数中的变量值可以对函数外的变量产生影响。

以下是一段示例代码:

#include <bits/stdc++.h>
using namespace std;
int main(){
    int a=0,b=100,c=300;
    auto f1=[&](){return a+c+b;};//合法
    auto f2=[&]()mutable{
        c*=b;
        a+=c;
        return a;};//合法 

    auto f3=[&]{c*=b;
        a+=c;
        return a;};//合法 以引用传入的变量不用mutable也能修改值
    f1();
    cout<<a<<" "<<b<<" "<<c<<endl; //打印结果为0 100 300
    f2();
    cout<<a<<" "<<b<<" "<<c<<endl; //打印结果为30000 100 30000
    f3();
    cout<<a<<" "<<b<<" "<<c<<endl; //打印结果为 3003000 100 3000000
    return 0;
}
混合捕获列表:
//以下的捕获列表都是合法的
[&var,=]//先用引用传入var,再将其他变量以值传递的方式传递
[a,&]//先用值传递的方式传入,再将其他变量以引用的方式传递
[this]//把this指针传入lambda函数中
[a,b,&]//与上面相似,下同
[a,b,=]
[a,b,……,&]
[a,b,……,=]

mutable:

mutable意为可变的,意思是将允许在lambda函数中修改以值传递捕获的变量。

以下是一段示例代码

#include <bits/stdc++.h>
int main(){
int a=0,b=200,c=100;
auto f2=[=]()mutable{
  c*=b;
  a+=c;
return a;};//合法 mutable解除了值传递进函数的const属性。
/*
auto f3=[=]{c*=b;
a+=c;
return a;};*/ //违法的,值传递进去的变量是const属性的,不能改变。
return 0;}//值得一提的是,本段示例代码中并未调用f2

指定返回类型

在lambda函数中,返回类型是可以由编译器自动推演的,但是如果需要指定的返回类型,可以在mutable后面添加→数据类型来指定,以下是一段示例代码:

#include <bits/stdc++.h>
using namespace std;
int main(){
    char c='a';
    int a=1;
  auto f1=[=](){
        return c-a;
    };
  cout<<f1()<<" ";//打印96 因为默认的返回类型是int
    auto f2=[=]()->char{
        return c+a;
    };
    cout<<f2();//打印b 因为我们指明了返回类型是char
  return 0;
}

语法总结:

综上,lambda的语法如下图所示
lambda语法

值得一提的是,可变规则与返回类型之前,可以进行异常的处理。

以下的部分是可以省略的:

  1. 可变规则(默认为可变的)

  2. 返回类型(默认编译器自动推演)

  3. 异常说明(若无声明,则无)

  4. 参数列表 注意 只有在将面世的c++23标准中,才可以省略不写参数列表

总结:

lambda 表达式是 C++11 最重要也最常用的一个特性之一,C# 3.5 和 Java 8 中就引入了 lambda 表达式。

lambda 来源于函数式编程的概念,也是现代编程语言的一个特点。C++11 这次终于把 lambda 加进来了。

lambda表达式有如下优点:

  • 声明式编程风格:就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象。以更直接的方式去写程序,好的可读性和可维护性。

  • 简洁:不需要额外再写一个函数或者函数对象,避免了代码膨胀和功能分散,让开发者更加集中精力在手边的问题,同时也获取了更高的生产率。

  • 在需要的时间和地点实现功能闭包,使程序更灵活。

善用lambda表达式可以有效地提升你的代码结构。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牧 渊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值