当前位置: 首页 > article >正文

(P33-P35)lambda表达式语法,lambda表达式注意事项,lambda表达式本质

文章目录

    • 1.lambda表达式语法
    • 2.捕获列表
    • 3.返回值
    • 5.lambda函数本质

1.lambda表达式语法

lambda 表达式是 C++11 最重要也是最常用的特性之一,这是现代编程语言的一个特点,lambda 表达式有如下的一些优点:

  • 声明式的编程风格:就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或函数对象。
  • 简洁:避免了代码膨胀和功能分散,让开发更加高效。
  • 在需要的时间和地点实现功能闭包,使程序更加灵活。
  • lambda表达式,就是匿名函数

lambda 表达式定义了一个匿名函数,并且可以捕获一定范围内的变量。

  • lambda 表达式的语法形式简单归纳如下:
[capture](params) opt -> ret {body;};其中 capture 是捕获列表,params 是参数列表,opt 是函数选项,ret 是返回值类型,body 是函数体。
  • 捕获列表 []: 捕获一定范围内的变量
  • 参数列表 (): 和普通函数的参数列表一样,如果没有参数参数列表可以省略不写。
auto f = [](){return 1;}	// 没有参数, 参数列表为空,一般都需要写上
auto f = []{return 1;}		// 没有参数, 参数列表省略不写
  • opt 选项, 不需要可以省略

mutable: 可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)
exception: 指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw ();

  • 返回值类型:在 C++11 中,lambda 表达式的返回值是通过返回值后置语法来定义的。(可以由编译器自动推导)
  • 函数体:函数的实现,这部分不能省略,但函数体可以为空。

2.捕获列表

lambda 表达式的捕获列表可以捕获一定范围内的变量,

  • 具体使用方式如下:
[] - 不捕捉任何变量[&] - 捕获外部作用域中所有变量,并作为引用在函数体内使用 (按引用捕获)[=] - 捕获外部作用域中所有变量,并作为副本在函数体内使用 (按值捕获)
拷贝的副本在匿名函数体内部是只读的[=, &foo] - 按值捕获外部作用域中所有变量,并按照引用捕获外部变量 foo[bar] - 按值捕获 bar 变量,同时不捕获其他变量[&bar] - 按引用捕获 bar 变量,同时不捕获其他变量[this] - 捕获当前类中的 this 指针
让 lambda 表达式拥有和当前类成员函数同样的访问权限
如果已经使用了 & 或者 =, 默认添加此选项
  • eg:
#include <iostream>
#include <functional>
using namespace std;class Test
{
public:void output(int x, int y){//x1:错误,没有捕获外部变量,不能使用类成员 m_numberauto x1 = [] {return m_number; };                      // error//x2:正确,以值拷贝的方式捕获所有外部变量auto x2 = [=] {return m_number + x + y; };             // ok//x3:正确,以引用的方式捕获所有外部变量auto x3 = [&] {return m_number + x + y; };             // ok//x4:正确,捕获 this 指针,可访问对象内部成员auto x4 = [this] {return m_number; };                  // ok//x5:错误,捕获 this 指针,可访问类内部成员,没有捕获到变量 x,y,因此不能访问。auto x5 = [this] {return m_number + x + y; };          // error//x6:正确,捕获 this 指针,x,yauto x6 = [this, x, y] {return m_number + x + y; };    // ok//x7:正确,捕获 this 指针,并且可以修改对象内部变量的值auto x7 = [this] {return m_number++; };                // ok}int m_number = 100;
};
  • eg:
int main(void)
{int a = 10, b = 20;//f1:错误,没有捕获外部变量,因此无法访问变量 aauto f1 = [] {return a; };                        // error//f2:正确,使用引用的方式捕获外部变量,可读写auto f2 = [&] {return a++; };                     // ok//f3:正确,使用值拷贝的方式捕获外部变量,可读auto f3 = [=] {return a; };                       // ok//f4:错误,使用值拷贝的方式捕获外部变量,可读不能写auto f4 = [=] {return a++; };                     // error//f5:错误,使用拷贝的方式捕获了外部变量 a,没有捕获外部变量 b,因此无法访问变量 bauto f5 = [a] {return a + b; };                   // error//f6:正确,使用拷贝的方式捕获了外部变量 a,只读,使用引用的方式捕获外部变量 b,可读写auto f6 = [a, &b] {return a + (b++); };           // ok//f7:正确,使用值拷贝的方式捕获所有外部变量以及 b 的引用,b 可读写,其他只读auto f7 = [=, &b] {return a + (b++); };           // okreturn 0;
}

在匿名函数内部,需要通过 lambda 表达式的捕获列表控制如何捕获外部变量,以及访问哪些变量。

  • 默认状态下 lambda 表达式无法修改通过复制方式捕获外部变量,如果希望修改这些外部变量,需要通过引用的方式进行捕获。

3.返回值

很多时候,lambda 表达式的返回值是非常明显的,因此在 C++11 中允许省略 lambda 表达式的返回值。

  • eg:
// 完整的lambda表达式定义
auto f = [](int a) -> int
{return a+10;  
};// 忽略返回值的lambda表达式定义
auto f = [](int a)
{return a+10;  
};
  • eg:一般情况下,不指定 lambda 表达式的返回值,编译器会根据 return 语句自动推导返回值的类型,但需要注意的是 labmda表达式不能通过列表初始化自动推导出返回值类型。
// ok,可以自动推导出返回值类型
auto f = [](int i)
{return i;
}// error,不能推导出返回值类型
auto f1 = []()
{//因为列表可以初始化int[],也可以初始化结构体,所以这里得指定返回值类型return {1, 2};	// 基于列表初始化推导返回值,错误
}

5.lambda函数本质

使用 lambda 表达式捕获列表捕获外部变量,如果希望去修改按值捕获的外部变量,那么应该如何处理呢?

  • 这就需要使用 mutable 选项,被mutable修改是lambda表达式就算没有参数也要写明参数列表,并且可以去掉按值捕获的外部变量的只读(const)属性。
int a = 0;
auto f1 = [=] {return a++; };              // error, 按值捕获外部变量, a是只读的
auto f2 = [=]()mutable {return a++; };     // ok
  • 什么通过值拷贝的方式捕获的外部变量是只读的:?

lambda表达式的类型在C++11中会被看做是一个带operator()的类,即仿函数。

按照C++标准,lambda表达式的operator()默认是const的,一个const成员函数是无法修改成员变量值的。

mutable 选项的作用就在于取消 operator () 的 const 属性。

  • 因为 lambda 表达式在 C++ 中会被看做是一个仿函数,因此可以使用std::function和std::bind来存储和操作lambda表达式:
#include <iostream>
#include <functional>
using namespace std;int main(void)
{// 包装可调用函数std::function<int(int)> f1 = [](int a) {return a; };// 绑定可调用函数std::function<int(int)> f2 = bind([](int a) {return a; }, placeholders::_1);// 函数调用cout << f1(100) << endl;cout << f2(200) << endl;return 0;
}

对于没有捕获任何变量的 lambda 表达式,还可以转换成一个普通的函数指针:

using func_ptr = int(*)(int);
// 没有捕获任何外部变量的匿名函数
func_ptr f = [](int a)
{return a;  
};
// 函数调用
f(1314);
  • 参考:Lambda 表达式
http://www.lryc.cn/news/2417686.html

相关文章:

  • mariaDB(mysql数据库)-安装配置和使用
  • 理解:QPS、TPS、RT、吞吐量
  • MinGW安装教程
  • Java中 static 关键字相关的用法
  • ADB 安装 + 打驱动全教程
  • 不同的存储库(Repository)模式实现
  • 开源项目 `signature` 使用教程
  • GCC详解-Binutils工具之strip
  • 消息传递机制之Handler使用总结
  • 一分钟快速过安卓四大组件——Activity篇
  • 2024年最新GIMP(Linux下的Photoshop)-KOS安装教程_linux photoshop
  • 19 张图概览 Spring Cloud(收藏夹吃亏系列)
  • linux后台运行nohup | 进程查看、终止 | linux基础命令记录
  • Mybatis-Plus理解及使用
  • 前端进阶之路——域名(domain)
  • win11下配置visual studio 2022+PCL1.13.0
  • 50个常用的 Numpy 函数详解!
  • kali简介
  • Java | final关键字快速上手【通俗易懂,看这篇就够了】
  • UUID介绍与生成方法
  • fps游戏战斗相关漫谈(五)
  • 安卓工程师必须了解的Gradle知识
  • ASCII码对照表(包括十六进制、十进制和字符)
  • 如何使用Chat GPT
  • 适合小白入门!Sqlite数据库学习(附操作过程截图)
  • 大白话讲vuex
  • 随记——ELK部署
  • Linux whois命令教程:查询域名所有者信息(附案例详解和注意事项)
  • SqlServer数据库安装及使用(第一篇)
  • Arduino入门