C++11的新特性:三、lambda表达式

在 C++ 里,Lambda 表达式为我们提供了一种简洁、高效的方式来定义匿名函数,它能够让代码更加紧凑和灵活,尤其在一些需要临时定义函数逻辑的场景下。

(一)Lambda 表达式

Lambda 表达式的基本语法如下:

[ capture list ] (parameters) -> return_type { function body }

[ capture list ]:捕获列表,它决定了 Lambda 表达式能够访问哪些外部变量,以及以何种方式访问(按值捕获或引用捕获)。如果不需要访问外部变量,这里可以为空 []

(parameters):参数列表,就像普通函数的参数一样,指定 Lambda 函数接受的输入参数。如果没有参数,括号也不能省略,写成 ()

-> return_type:返回值类型指示符,用于明确 Lambda 函数的返回值类型。如果编译器能够自动推断返回值类型,这部分可以省略,让编译器自动完成推断工作。

{ function body }:函数体,包含了 Lambda 函数具体要执行的代码逻辑,与普通函数的函数体类似。

(二)示例

// 示例 1:无参数、无返回值,仅仅打印一条信息
auto fun3 = []() {cout << "[] ()" << endl; };
fun3();

// 示例 2:无参数,有返回值
auto fun5 = [] {cout << "fun 5 run" << endl; return 5; };
int num5 = fun5();
cout << num5 << endl;

// 示例 3:有参数,有返回值
auto fun1 = [](int a, int b) -> int { cout << a << " " << b << endl; return a * b; };
int num1 = fun1(2, 3);
cout << num1 << endl;

在示例 1 中,[]() 定义了一个无参数的 Lambda 表达式,函数体里只是简单地向控制台输出一条信息。调用 fun3() 就能执行这个匿名函数。
示例 2 同样无参数,但它有返回值。当调用 fun5() 时,先打印信息,然后返回值 5 被赋给 num5 并输出。
示例 3 是一个更常见的形式,接受两个整数参数 a 和 b,在函数体中先打印这两个参数,然后返回它们的乘积。通过 fun1(2, 3) 调用,传入实际参数 2 和 3,得到结果并输出。

(三)捕获外部变量

这可是 Lambda 表达式的一个关键特性,它让 Lambda 函数能够与外部环境进行交互。

1.按值捕获

int main()
{
    Int a(10);
    // 按值捕获 a,会用 a 拷贝构造一个副本,只可读,不可写
    auto fun = [a](int x)->int {return a.GetValue() + x; }; 
    int num = fun(10);
    cout << num << endl;
}

这里定义了一个 Int 类型的变量 a,在 Lambda 表达式 [a](int x)->int {return a.GetValue() + x; } 中,[a] 表示按值捕获 a。这意味着 Lambda 函数内部使用的是 a 的一个副本,它不能修改外部原始的 a。当调用 fun(10) 时,将 a 的值(通过 GetValue 函数获取)与传入的参数 10 相加,返回结果。

2.引用捕获

int main()
{
    Int a(10);
    // 引用捕获不会建立副本,可读可写
    auto funa = [&a](int x)->int 
    {
        cout << a.GetValue() << endl;
        a.SetValue(100);
        return x + 10;
    };

    int c = funa(10);
    cout << c << endl;
    a.SetValue(200);
    c = funa(10);
    cout << c << endl;
}

在这个例子中,[&a] 采用引用捕获方式。此时,Lambda 函数内部操作的就是外部原始变量 a,可以读取它的值(通过 GetValue 打印),也能修改它的值(通过 SetValue)。第一次调用 funa(10),修改 a 的值为 100,后续再次修改 a 为 200 并重新调用 funa,输出结果会随之变化,充分体现了引用捕获的特性。

3.混合捕获

int main()
{
    Int valx(10);
    Int* thiz = &valx;
    auto fun = [thiz, valx] {
        cout << "&valx:" << &valx << endl;
        thiz->GetValue();
        thiz->SetValue(100);
    };
    fun();
    cout << "&valx:" << &valx << endl;
    cout << valx << endl;
}

这里出现了混合捕获,[thiz, valx] 既按值捕获了 valx,又捕获了指向 valx 的指针 thiz。在 Lambda 函数内部,可以打印 valx 的地址(虽然是副本的地址),通过指针 thiz 操作原始的 valx 对象,调用 GetValue 和 SetValue 函数。执行完 Lambda 函数后,再打印外部原始 valx 的地址和值,能清晰看到值已经被 Lambda 函数内部通过指针修改。

(四)全局变量与 Lambda

Int tmp(10);//全局作用域不存在捕获
void func()
{
    tmp.SetValue(100);
}
int main()
{
    cout << tmp.GetValue() << endl;
    auto funa = []() { cout << tmp.GetValue() << endl; };
}

这里定义了全局变量 tmp,在 main 函数中的 Lambda 表达式如果想要访问它,可以直接在捕获列表为空的情况下使用(前提是全局变量有合适的访问权限)。即当 Lambda 函数需要用到全局数据时,无需特别捕获,直接操作即可(要遵循作用域和访问规则)。

(五)总结

Lambda 表达式为 C++ 编程带来了极大的便利,让我们能在需要的地方快速定义小型、针对性强的函数逻辑。通过灵活运用捕获列表,能够精细控制与外部环境的交互方式,无论是按值捕获保证数据只读性,还是引用捕获实现实时数据共享与修改,亦或是混合捕获满足复杂需求,都让代码更加简洁高效。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值