【6】c++11新特性(稳定性和兼容性)—>Lambda表达式

基本用法

lambda表达式是c++最重要也是最常用的特性之一,这是现代编程语言的一个特点,lambda表达式有如下的一些优点:
(1)声明式的编成风格:就地匿名定义目标函数活着函数对象,不需要额外写一个命名函数或者函数对象;
(2)简洁:避免了代码膨胀和功能分散;
(3)在需要的时间和地点实现功能闭包,是程序更加灵活。
lambda表达式定义了一个匿名函数,并且可以捕获一定范围内的变量。lambda表达式的语法形式简答归纳如下:

[capture](params)opt->ret{body;}

capture:变量捕获列表;
params:参数列表,类似函数参数;
opt:函数选项;
ret:返回值类型;
body:函数体;
1.捕获列表[]:捕获一定范围内的变量;
2.参数列表():和普通函数的参数列表一样,如果没有参数列表可以不写。

auto f = [](){return 1};
auto f = []{return 1};  

3.opt:不需要时可以省略

  • mutable:可以修改按值传递进来的拷贝(注意时能修改拷贝,而不是值本身);
  • exception:指定函数抛出的异常,如抛出整数类型的异常,可以使用throw。
    4.返回值类型:在c++11中,lambda表达式的返回值是通过返回值后置语法来定义的。
    5.函数体:函数的实现,这部分不能省略,但函数体可以为空。

捕获列表

  • [] : 不捕捉任何变量;
  • [&] : 捕获外部作用域中所有变量,并作为引用在函数体内使用(按引用捕获);
  • [=] : 捕获外部作用域中所有变量,并作为副本在函数体内使用(按值捕获);拷贝的副本在匿名函数体内部是只读的;
  • [=,&foo] : 按值捕获外部作用域中所有变量,并按照引用捕获外部变量foo;
  • [bar] : 按值捕获bar变量,同时不捕获其他变量;
  • [&bar] : 按引用捕获bar变量,同时不捕获其他变量;
  • [this] : 捕获当前类中的this指针。
    让lambda表达式拥有和当前类成员函数同样的访问权限;
    如果已经使用了&或者=,默认添加此选项。
类中使用lambda
#include <iostream>

class Test
{
public:
    void output(int x, int y)
    {
        auto x1 = [] {return 1; };  //ok
        auto x1 = [] {return m_number}; //error,没有捕获外部变量,因此不能使用m_number
        auto x2 = [=] {return m_number + x + y; }; //ok,以值拷贝方式的方式捕获所有外部变量
        auto x3 = [this] {return m_number; }; //ok,捕获this指针,可访问对象内部成员
        auto x4 = [&] {return m_number + x + y; }; //ok,以引用方式捕获所有外部变量
        auto x5 = [this] {return m_number + x + y; }; //error,没有捕获x,y,所以不能使用x,y
        auto x6 = [this, x, y] {return m_number + x + y; };//ok,
        auto x7 = [this] {return m_number++; }; //ok,正常捕获this指针,并且可以修改对象内部变量的值
    }
    int m_number = 100;
};

int main()
{
    std::cout << "Hello World!\n";
}
函数中使用lambda
int main(void)
{
    int a = 10, b = 20;
    auto f1 = [] {return a; };  // error,未捕获a
    auto f2 = [&] {return a++; }; // ok,引用方式捕获
    auto f3 = [=] {return a; };   // ok,值拷贝,只读
    auto f4 = [=] {return a++; };  //error,值拷贝,只读,不可以修改
    auto f5 = [a] {return a + b; }; // error,未捕获b
    auto f6 = [a, &b] {return a + (b++); }; // ok,
    auto f7 = [=, &b] {return a + (b++); }; // ok

    return 0;
}

注:在匿名函数内部,需要通过lambda表达式的捕获列表控制如何捕获外部变量,以及访问哪些变量。默认状态下lambda表达式无法修改通过复制方式捕获外部变量,如果希望修改这些外部变量,需要通过引用的方式进行捕获。

在这里插入图片描述
为什么m_number_1可以修改,m_number_2不可以修改?
在这里插入图片描述
在这里插入图片描述

返回值

c++中允许省略lambda表达式的返回值类型

// 完整的lambda表达式定义
auto f = [](int a) -> int   //int类型可以忽略不写
{
    return a+10;  
};

// 忽略返回值的lambda表达式定义
auto f = [](int a)
{
    return a+10;  
};

如果不指定lambda表达式的返回值,编译器会根据return语句自动推导返回值类型,但需要注意的是lambda表达式不能通过列表初始化自动推导出返回值类型

// ok,可以自动推导出返回值类型
auto f = [](int i)
{
    return i;
}

// error,不能推导出返回值类型
auto f1 = []()
{
    return {1, 2};	// 基于列表初始化推导返回值,错误
}

函数本质

使用lambda表达式捕获列表捕获外部变量,如果希望去修改按值捕获的外部变量,那么应该如何处理呢?这就需要使用mutable选项,被mutable修改时lambda表达式就算没有参数也要谢敏参数列表,并且可以去掉按值捕获的外部变量的只读(const)属性。
在这里插入图片描述
最后再剖析一下,为什么通过值拷贝的方式捕获外部变量是只读的:
1.lambda表达式的类型在c++11中会被看成是带operator()的类,即仿函数;
2.按照c++标准,lambda表达式的operator()默认是const的,一个const成员函数是无法修改成员变量值的。
mutable选项的作用就是取消const属性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

<( ̄︶ ̄)Okay.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值