IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【C++】Lambda 表达式详解 -> 正文阅读

[C++知识库]【C++】Lambda 表达式详解

一、Lambda表达式简介

  • Lambda 表达式是 C++11 中语法之一
  • Lambda 表达式把函数看作对象,把这个表达式当做对象使用
  • Lambda 表达式可以赋值给变量,也可以当做参数传给真正的函数

二、Lambda表达式语法解析

1. Lambda exp 基本语法结构

[ /* captures */ ] /* <tparams> */ ( /* params */ ) /* -> retType */ { /* body */ }	
  • captures : 捕获变量列表,该 Lambda 表达式上下文中的变量都可以放在 captures 中,以供 body 中使用,如果程序上下文中的变量不会在 body 中用到,可以不传入
  • tparams :模板参数列表,可省略
  • params:传入的参数列表,若没有参数,可省略()
  • retType:返回值类型,以下两种情况可以不写:①无返回值 ②返回值可以被编译器推导
  • body:函数体,用于编写具体函数逻辑的地方
  • 其中的 tparams \ params \ retType 都可以省略,最简单的表达式结构: [ ] { }

2. 捕获变量的几种方式

你可以通过按值传递按引用传递的方式捕获变量:

  • [&epsilon] 将参数 epsilon 按引用传递给Lambda表达式
  • [epsilon] 参数 epsilon 按传递给Lambda表达式
  • [&] 通过按引用捕获 Lambda 表达式中使用的所有变量
  • [=] 通过按捕获 Lambda 表达式中使用的所有变量
  • [&, epsilon] 除了参数 epsilon 按传递,其他变量都按引用传递
  • [=, &epsilon] 除了参数 epsilon 按引用传递,其他变量都按传递

具体解释:

  1. 按值捕获:只可以输出内容,不可以对内容进行修改,捕捉列表中的变量为只读,是原变量的一份拷贝
int a = 10;
auto lmd = [a] () {
    cout << a << endl; 	// 合法操作
	a += 2; 			// 非法操作
}
  1. 按引用捕获:获得该变量的引用,可以对该变量进行任何操作
int a = 10;
auto lmd = [&a] () {
    cout << a << endl; 	// 合法操作
	a += 2; 			// 合法操作
}
  1. [=] 按值捕获所有能捕获的变量:也可以捕获this指针

  2. 使用 [&] 按引用捕获所有能捕获的变量,也可以将其他变量单独按值捕获,例如:[&, param1, param2]

#include <iostream>
#include <string>
using namespace std;
class Date{
    private:
        int _year;
        int _month;
        int _day;
    public:
        Date(int y, int m, int d):_year(y), _month(m), _day(d){}
        void showDate()
        {
            string s = "Today is ";
            auto show = [=](){
                cout << s << this->_year << " : " << this->_month << " : " << this->_day << endl;
            };
            show();
        }
};
int main()
{
    Date d(2020, 7, 4);
    d.showDate();
    return 0;

注意:如果不使用=来捕捉,必须将this传进Lambda表达式中,要不然会报以下错误

 error:this’ was not captured for this lambda function

3. mutable关键字

  • 如果使用按值捕获,并且想修改拷贝的值,可以使用mutable关键字修饰
int a = 10;
auto lmd = [a] () mutable {
    cout << a << endl; 	// 10
	a += 2; 			// 合法操作,并且不影响 lambda 表达式外面的变量a的值
    cout << a << endl; 	// 12
}
cout << a << endl; 	// 10

三、Lambda表达式使用示例

  • 将 Lambda 表达式当做函数对象使用
#include <iostream>
using namespace std;

int main()
{
    int a = 10, b = 4;
    auto lamb = [&a, &b](int&& x, int&& y) -> void {
        cout << a << " " << b << " " << x << " " << y << endl;
    };
    lamb(1, 2);

    return 0;
}
  • 将 Lambda 表达式当做函数参数使用:常用于替换仿函数
/* 对自定义结构排序 */
#include <iostream>
#include <algorithm>
using namespace std;

struct S
{
    int x;
    int y;
}s[2];

int main()
{
    s[0].x = 0, s[0].y = 2;
    s[1].x = 0, s[1].y = 3;
    sort(s,s + sizeof(s) / sizeof(s[0]), [](S& a, S& b){
        if(a.x == b.x)
            return a.y > b.y;
        return a.x > b.x;
            });
    for(auto e : s)
        cout << e.x << " " << e.y << endl;

    return 0;
}

四、探究Lambda表达式的实现原理

  • 我们发现 Lambda表达式 和 函数对象 极其相似,故我们可以对比看看他俩的汇编代码如何
class Rate
{
public:
	Rate(double rate) : _rate(rate){}
	double operator()(double money, int year){
		return money * _rate * year;
	}
private:
	double _rate;
};
int main()
{
	double rate = 0.49;

	// 函数对象
	Rate r1(rate);
	r1(10000, 2);	

	// lambda exp
	auto r2 = [=](double monty, int year)->double{
		return monty * rate * year; 
	};
	r2(10000, 2);

	system("pause");
	return 0;
}

汇编代码对比

image-20210704203429574

由此可见,Lambda表达式其实也是一个函数对象,也是调用了 operator() 来实现 Lambda表达式 的

五、不可省去返回值的情况

当你的返回值可能会出现多种数据类型的情况下,编译器无法自动推导出具体返回值类型,这时,便必须指明返回值类型,例如:

void func4(std::vector<double>& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) {
            if (d < 0.0001) {
                return 0;	// int
            } else {
                return d;	// double
            }
        });
}

以上代码必须使用-> T的方式来告诉编译器,返回值究竟使用什么数据类型

void func4(std::vector<double>& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) -> double {
            if (d < 0.0001) {
                return 0;	// 相当于 (double)0
            } else {
                return d;
            }
        });
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-06 23:57:47  更:2021-07-06 23:58:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 8:05:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码