第三章 语言运行期的强化——Lambda 表达式

3.1 Lambda 表达式

Lambda 表达式提供了一个类似于匿名函数的特性。

匿名函数是在一个需要函数,但是又不想费力去命名一个函数的情况下去使用的。这样的场景其实在现代编程语言中有很多,所以匿名函数几乎是现代编程语言的标配。

基础

Lambda 表达式基本语法如下:

[捕获列表](参数列表)mutable(可选) 异常属性 -> 返回类型
{
    //函数体
}

上面的语法规则都很好理解,可能[捕获列表]困难一点。

Lambda 表达式内部函数体在默认情况下是不能使用函数体外部的变量的。通过捕获列表,可以起到传递外部数据的作用。根据传递的行为,有以下几种:

1. 值捕获

与参数按照值传递类似,值捕获的前提是要捕获的对象可以拷贝。和值传递不同的是,不捕获的变量在 Lambda 表达式被创建时拷贝,而不是被调用时拷贝。如下代码:

void lambda_value_capture()
{
    int value = 1;
    auto copy_value = [value] {
        return value;
    };
    value = 100;
    auto stored_value = copy_value;  // stored_value == 1
    //因为 copy_value 在创建时就拷贝了一份 value
}

2. 引用捕获

与引用传参类似,引用捕获保存的是引用。如果修改引用,原来的值会发生变化。

void lambda_reference_capture()
{
    int value = 1;
    auto copy_value = [&value] {
        return value;
    };
    value = 100;
    auto stored_value = copy_value();  //stored_value == 100
    //因为 copy_value 保存的是引用
}

3. 隐式捕获

手动写捕获列表有时候很麻烦,可以把这种机械性的工作交给编译器。可以在捕获列表中写一个 & 或 = 向编译器声明采用的捕获方式。

小总结

常用的四种捕获方式:

1.[] 空捕获列表

2.[name1, name2, …] 捕获一系列的变量

3.[&] 引用捕获,让编译器自行推导

4.[=] 值捕获,让编译器自行推导

4.表达式捕获

这里涉及到后面的右值引用以及智能指针。

上面提到的值捕获、引用捕获都是已经在外层作用域声明的变量,这些变量均为左值。

C++14 允许捕获的成员用任意的表达式进行初始化,这就允许了右值的捕获。被声明的捕获变量类型会根据表达式进行判断,判断方式与使用 auto 本质上是相同的(需要提供足够的信息,可以让编译器推导出类型)。如下代码:

#include <iostream>
#include <memory>  //make_unique
#include <utility>  //move
using namespace std;

void lambda_expression_capture()
{
    auto important = make_unique<int>(1);
    auto add = [v1 = 1, v2 = move(important)](int x, int y) -> int
    {
        return x + y + v1 + (*v2);
    };
    cout << add(3, 4) << endl;  //输出 9
}

上面的代码中,important 是一个独占指针,不能被值捕获,我们将其转为右值,在表达式中进行初始化。

泛型 Lambda

在 C++11 中,auto 关键字不能出现在参数列表里。从 C++20 起,auto 关键字可以出现在参数列表中。

从 C++14 起,Lambda 函数的形参列表就可以使用 auto 关键字来进行类型推导。如下代码:

auto add = [](auto x, auto y)
{
    return x + y;
};

cout << add(1, 2) << endl;  //合法,结果为 3
cout << add(1.1, 2.2) << endl;  //合法,结果为 3.3

总结

在实际开发中,Lambda 表达上从来不像上面例子中那样使用。文章中只是为了讲解,省去了其他复杂的代码,进行了不太合理的操作。

一开始就说了,Lambda 表达式提供了一种类似于匿名函数的性质。上面的所有代码,全部都背离了这个初衷。

比如 add 这个函数,已经不算是一个匿名函数了。add 就是函数名称,后面也可以通过这个函数名称调用该函数。这样,我直接定义一个真正的函数多好,而且能够大幅度提升可读性。

实际开发中,Lambda 表达式往往配合容器、算法等 STL 相关的东西使用。

大家学习 STL 的时候,一定知道一些容器、算法可以自定义规则。这个自定义的规则通过仿函数实现。

Lambda 表达式天生适配仿函数。所以,Lambda 表达式大多数时候都是作为仿函数去使用。

在虚幻四引擎中,虚幻的 TMap、TArray等容器,以及 Sort、Find 等算法,都可以使用 Lambda 表达式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值