【C++】Lambda表达式的使用

这篇具有很好参考价值的文章主要介绍了【C++】Lambda表达式的使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

学习目标:

例如:

  • 了解Lambda的优点
  • 掌握Lambda表达式的使用
  • 了解Lambda表达式的底层原理

学习内容:

  1. Lambda表达式的语法

【C++】Lambda表达式的使用,c++,开发语言

Lambda表达式

lambda表达式的底层实现涉及到闭包(Closure)的概念。闭包是一个函数对象,它可以捕获外部作用域中的变量,并在其生命周期内访问和修改这些变量。lambda表达式的底层实现就是通过创建闭包来实现的。

具体而言,lambda表达式在底层会被转化为一个函数对象。这个函数对象中包含了捕获的外部变量,并且重载了函数调用运算符operator()。函数对象可以像普通的函数一样被调用,其执行的代码就是lambda表达式中的代码。

lambda表达式的展开过程包括以下几个步骤:

  1. 语法解析:将lambda表达式解析为函数对象的声明和定义。
  2. 生成函数对象:根据lambda表达式的参数、返回类型和捕获列表等信息,生成一个函数对象。
  3. 生成仿函数类:根据生成的函数对象,生成一个仿函数类(Functor),其中重载了函数调用运算符operator()
  4. 类型推导:根据lambda表达式中的代码和上下文,进行类型推导,确定函数对象的参数类型和返回类型。
  5. 生成代码:根据类型推导的结果,生成调用函数对象的代码。
  6. 调用lambda表达式:通过调用函数对象的operator(),执行lambda表达式中的代码。

排序案例

对于一个简单的数组来说:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main(void)
{
	vector<int>arr = { 9,8,5,6,3,2,1,5,12,13,14,520 };

	sort(arr.begin(), arr.end());
	for (auto& e : arr)
	{
		cout << e << " ";
		e++;
	}
	cout << endl;

	sort(arr.begin(), arr.end(), greater<int>());
	for (auto& e : arr)
	{
		cout << e << " ";
		e++;
	}
	return 0;
}

这样排序和简单,但是实际开发当中都是在类当中排序,如下。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

struct Goods
{
	string _name;  // 名字
	double _price; // 价格
	int _evaluate; // 评价
	Goods(const char* str, double price, int evaluate)
		:_name(str)
		, _price(price)
		, _evaluate(evaluate)
	{}
};
struct ComparePriceLess
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._price < gr._price;
	}
};

struct ComparePriceGreater
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._price > gr._price;
	}
};


int main(void)
{
	vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,3 }, { "菠萝", 1.5, 4 } };
	sort(v.begin(), v.end(), ComparePriceGreater());
	for (auto& e : v)
	{
		cout << e._name<<" "<<e._price<<" "<<e._evaluate<<endl;
	}
	cout << "==============================" << endl;
	sort(v.begin(), v.end(), ComparePriceLess());
	for (auto& e : v)
	{
		cout << e._name << " " << e._price << " " << e._evaluate << endl;
	}
	return 0;
}

每一种排序方式都要写一个类,然后重载operator(),这样是不是有点太麻烦了,因此,C++11增加了Lambda表达式,来简化这一过程。

如下是Lambda表达式的使用样例:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

struct Goods
{
	string _name;  // 名字
	double _price; // 价格
	int _evaluate; // 评价
	Goods(const char* str, double price, int evaluate)
		:_name(str)
		, _price(price)
		, _evaluate(evaluate)
	{}
};



int main(void)
{
	vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,3 }, { "菠萝", 1.5, 4 } };
	sort(v.begin(), v.end(), [](Goods& s1, Goods& s2)->bool{
		return s1._price < s2._price;
		});
	for (auto& e : v)
	{
		cout << e._name<<" "<<e._price<<" "<<e._evaluate<<endl;
	}
	cout << "==============================" << endl;
	sort(v.begin(), v.end(), [](Goods& s1, Goods& s2)->bool {
		return s1._price > s2._price;
		});
	for (auto& e : v)
	{
		cout << e._name << " " << e._price << " " << e._evaluate << endl;
	}
	return 0;
}

其实Lambda表达式就是一个匿名函数。

Lambda表达式语法

语法格式:[捕捉列表](参数列表)mutable->返回类型{函数体}

捕捉列表 能够捕捉当前栈帧的所有对象(全局的也可以捕捉到)
参数列表 和函数中的参数列表一样,int a,int b这些
mutable 默认情况下Lambda表达式是一个const函数,不能被修改,而mutable可以取消const,可以对参数进行修改
返回类型 返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回 值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推 导。
函数体 函数的具体实现,在该函数体内,除了可以使用其参数外,还可以使用所有捕获 到的变量。

C++中最简单的Lambda表达式:[]{},但它并不能干什么。

#include<iostream>
using namespace std;

int main(void)
{
	int a = 1, b = 2,c=5;
	auto func1=[=] {return a + b; };
	cout << func1() << endl;
	auto func2 = [=](int a, int b) {return a + b + c; };
	cout << func2(a,b)<<endl;
	auto fun2 = [=, &b](int c)->int {return b += a + c; };
	cout << fun2(10) << endl;

	return 0;
}

捕捉列表

lambda函数在捕获外部变量时会创建一个闭包。闭包是指一个函数对象,它包含了函数定义时的环境信息,包括捕获的外部变量。通过捕获外部变量,lambda函数可以在其定义的作用域之外使用这些变量。闭包的存在使得lambda函数可以延长外部变量的生命周期,并且可以在函数调用结束后仍然访问这些变量。这是lambda函数的一个非常强大的特性。

[var] 捕捉值传递变量var
[=] 表达值传递的所有变量(当前栈帧)
[&var] 捕捉引用传递变量var
[&] 捕捉引用传递的所有变量(当前栈帧)、包括this
[this] 捕捉当前的this

Tip🎉:

1.语法上捕捉列表可由多个捕捉项组成,并以逗号分割。

比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量 [&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量

2.捕捉列表不允许变量重复传递,否则就会导致编译错误。 比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复。

3.在块作用域以外的lambda函数捕捉列表必须为空。

4.Lambda表达式之间不能相互赋值,即使看起来类型相同。

void (*PF)();
int main()
{
 	auto f1 = []{cout << "hello world" << endl; };
 	auto f2 = []{cout << "hello world" << endl; };
    // 此处先不解释原因,等lambda表达式底层实现原理看完后,大家就清楚了
 	//f1 = f2;   // 编译失败--->提示找不到operator=()
    // 允许使用一个lambda表达式拷贝构造一个新的副本
 	auto f3(f2);
 	f3();
 	// 可以将lambda表达式赋值给相同类型的函数指针
 	PF = f2;
 	PF();
 	return 0;
}

Lambda表达式模拟

	auto print = [] {cout << "hello world"; };
	print();

比如这样的一个表达式,机器会自动翻译为如下的代码:

	class __lambda_Print_123
	{
	public:
		void operator()(void)
		{
			cout << "hello world" << endl;
		}
	};

还有这样的

	int a = 5, b = 2;
	auto Add = [](int a, int b)->int {return a + b; };

会翻译成如下代码:文章来源地址https://www.toymoban.com/news/detail-631664.html

	class __lambda_Add_123 {
	public:
		int operator()(int a, int b) const {
			return a + b;
		}
	};

到了这里,关于【C++】Lambda表达式的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++的lambda表达式(匿名函数)

    从C++11开始,C++也支持使用lambda表达式(匿名函数)。Lambda表达式是一种便捷的方式,可以定义一个函数对象,而无需使用显式的函数对象类型或函数指针语法。 C++中的 lambda表达式的基本语法如下: 其中各个部分的含义如下: capture list :用于指定所捕获的外部变量列表。可

    2024年02月08日
    浏览(46)
  • 【C++】C++11——lambda表达式

    我们之前都是通过函数指针、仿函数的方式可以像函数使用的对象,在C++11之后,就有了Lambda表达式 为了实现一个比较算法, 都要重新去写一个类,如果每次比较的逻辑不一样,还要去实现多个类,特别是相同类的命名,看代码的人就遭殃了,非常的烦,这些都非常地不方便

    2024年01月17日
    浏览(52)
  • C++ Lambda表达式的常见用法

    ⭐️我叫忆_恒心,一名喜欢书写博客的在读研究生👨‍🎓。 如果觉得本文能帮到您, 麻烦点个赞 👍呗! 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三连支持一下呗。👍⭐️❤️ 作为C++11的新特性的Lambada表达式本身

    2024年01月16日
    浏览(72)
  • 【C++】C++11语法 ~ lambda 表达式

    (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是 Scort 目前状态:大三非科班啃C++中 🌍博客主页:张小姐的猫~江湖背景 快上车🚘,握好方向盘跟我有一起打天下嘞! 送给自己的一句鸡汤🤔: 🔥真正的大师永远怀着一颗学徒的心 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏 🎉🎉

    2024年01月20日
    浏览(62)
  • C++系列十:日常学习-Lambda表达式

    目录 前言 必备理论知识: 例子: 20230920 加 例如 对函数指针和指针函数补充: 有C#经验,使用起来,驾轻就熟。 就是语法糖。但是也要熟悉用法,才好众享丝滑。 内容参考: Chatjpt、文心一言 C++ lambda 表达式是一种功能强大的编程工具,它允许您在代码中创建匿名函数或闭

    2024年02月08日
    浏览(54)
  • 【javaSE】 Lambda表达式与Lambda表达式的使用

    Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda 表达式(Lambda expression) ,基于数学中的λ演算得名,也

    2024年02月08日
    浏览(62)
  • Java语言----反射、枚举以及lambda表达式

    目录 一.反射 1.1反射的基本情况 1.2反射中最重要的类 1.2.1 Class类 1.2.2Field类 1.2.3Constructor类 1.2.4Method类 1.3反射优缺点  二.枚举 2.1概念 2.2枚举(enum)类方法 2.3枚举的构造 三.Lambda表达式 3.1Lambda介绍 3.2 函数式接口 3.3使用lambda表达式 3.2.1不使用Lambda表达式调用 3.2.2使用Lambda表

    2024年02月08日
    浏览(48)
  • C++ lambda表达式函数递归调用简单写法实现

    在C++11中,lambda表达式函数递归往往会带上 functional 头文件。书写形式如下: 还有相对简单点的第二种写法(C++14): 对于第二种, auto fib 的作用是为了在 lambda 表达式内部能够递归调用自身。在 C++14 中,lambda 表达式默认是无法直接递归调用的,因为在 lambda 内部无法访问到

    2024年02月15日
    浏览(50)
  • C++结合Lambda表达式在函数内部实现递归

    529. 扫雷游戏 已解答 中等 相关标签 相关企业 让我们一起来玩扫雷游戏! 给你一个大小为  m x n  二维字符矩阵  board  ,表示扫雷游戏的盘面,其中: \\\'M\\\'  代表一个  未挖出的  地雷, \\\'E\\\'  代表一个  未挖出的  空方块, \\\'B\\\'   代表没有相邻(上,下,左,右,和所有4个

    2024年02月21日
    浏览(42)
  • Learning C++ No.30 【lambda表达式实战】

    北京时间:2023/6/9/9:13,今天8:15起床,可能是最近课非常少,导致写博客没什么压力,什么时间都能写,导致7点起不来,哈哈哈,习惯睡懒觉了,但是问题不大,还在可控范围内,并且就在前天下午,我们进行了学校MySQL的期末考试,大一就学MySQL,我甚是想吐糟,实操题对于

    2024年02月08日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包