lambda表达式

一、简介

C++11才开始具备lambda表达式这种特性

lambda表达式的基本语法:

[captures](params)specifiers exception -> ret {body}

eg:
int x = 5;
auto foo = [x](int y)->int {
    return x*y;
}
cout<<foo(8)<<endl;

captures是捕获列表,它可以捕获当前函数所在作用域中零或多个变量

params是参数列表

specifiers是可选限定符,如mutable(允许在函数体内改变按值捕获的变量 或 调用非const类型修饰的成员函数)

exception是可选异常说明符,可以使用noexcept来指明表达式lambda是否会抛出异常

return 返回值类型

body函数体

二、lambda表达式捕获列表

1、捕获列表的作用域

捕获列表中的变量存在于两个作用域中,分别是定义lambda表达式的函数作用域,一个是lambda表达式函数体的作用域,所以标准规定捕获的变量必须是一个自动存储类型。

int x= 0;

int main()
{
    int y = 0;
    static int z = 0;
    auto foo = [x, y, z] {};

    return 0;
}

如x和z都不是自动存储类型的变量,所以无法编译通过,不过不同编译器的处理方式不同,比如GCC编译器只会发出警告

2、捕获值和捕获引用

int x = 5, y = 8;
auto foo1 = [x, y] {return x * y};
auto foo2 = [&x, &y] {return x * y};

3、特殊的捕获方法

[this]-捕获this指针,捕获this指针可以让我们使用this类型的成员变量和函数

[=]-捕获定义作用域的全部变量的值,包括this

[&]-捕获定义作用域的全部变量的引用,包括this

在C++20中,无状态的lambda表达式是可以隐式转换成函数指针的

void func(void(*)()) {}
void g() {
    func([](){});//编译成功
}

这一点在需要函数回调为参数的函数中是比较有用的

在STL中应用lambda表达式是比较方便的

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> x = {1, 2, 3, 4, 5};
    cout<<find_if(x.cbeign(), x.cend(), [](int i){
        return (i%3) == 0;
    })
    
}

例如sort和find_if,这些函数都是需要辅助函数或者辅助对象对象来帮助完成算法的,这种情况下使用lambda表达式可以让代码看起来非常的直接。

4、广义捕获

简单捕获:前面介绍的内容

初始化捕获:如下图

int main() {
    int x = 5;
    auto foo = [r = x + 1]() {
        return r;
    }
}

x所在的作用与是main函数,r所在的作用域是lambda表达式,这就是等号左右作用域的区别

初始化捕获的一大好处是可以方便的对捕获的对象进行处理

另外在C++14标准中还支持泛型lambda表达式,这里的泛型并没有使用模版,而是通过auto占位符来完成的。

int main() {
    auto foo = [](auto a) {return a;};
    foo(3);
    foo("hello lambda!");
}

代码中的foo就是一个典型的泛型lambda表达式。

5、其他特性

1、捕获[*this]和捕获[=, this]

捕获*this的目标是拷贝this对象,并且在lambda表达式中使用拷贝的对象,这种用法常用语一些异步的函数中,而[=, this]是直接使用this对象与 [=]意思是相同的。

2、模版语法的泛型lambda表达式

C++20标准为了让泛型表达式使用起来更加方便,引入了模版语法的泛型lambda表达式,这就和函数模版没有区别了

auto f = []<typename T>(vector<T> vector) {
    // ...
}

3、可构造和可赋值的无状态lambda表达式

最后C++20 的标准还允许构造和赋值无状态的lambda表达式

auto greater = [](auto x, auto y) {return x > y;};
map<string, int, decltype(greater)> mymap;

这里greater是一个无状态的lambda表达式,map模版的第3个形参需要一个比较函数的类型,在C++20之前使用decltype获取lambda表达式的类型并且作为模版实参传入map是不能编译通过的。因为map在使用这个参数时会构造出对象,而在C++20 之前lambda表达式类型是无法构造出对象的,C++20标准解决了这个问题,对于无状态的lambda表达式类型是可以构造和赋值的.

总结:

lambda表达式解决了过去C++中无法就地编写内嵌函数的尴尬问题,虽然GCC中提供了一种嵌套函数的C语言扩展,不过这个特性一直没有纳入标准之中。合理使用lambda表达式可以让我们的代码更加具有可读性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值