C++lambda表达式

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

C++lambda表达式,C++修仙 筑基中,c++,开发语言

                                                         🎬慕斯主页修仙—别有洞天

                                                         ♈️今日夜电波:Duvet—Bôa

                                                                2:55━━━━━━️💟──────── 4:29
                                                                    🔄   ◀️   ⏸   ▶️    ☰  

                                      💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍


目录

一、什么是lambda表达式?

二、lambda表达式详解

      捕捉列表

[var]:表示值传递方式捕捉变量var

[&var]:表示引用传递捕捉变量var

[=]:表示值传递方式捕获所有父作用域中的变量(包括this) 

[&]:表示引用传递捕捉所有父作用域中的变量(包括this)

[this]:表示值传递方式捕捉当前的this指针 

[=,&]:拷贝与引用混用

      返回值类型

      其余部分

三、lambda与仿函数的对比 

底层观察:

lambda与仿函数的异同


一、什么是lambda表达式?

        C++ Lambda 表达式是一种匿名函数,它可以像变量一样被定义、传递和赋值,大大简化了 C++ 的编程过程。Lambda 表达式的语法形式如下:

[capture-list] (parameters) -> returntype {statement}

对于以上各个部分的解析:

        [capture-list] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。

        (parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略

        mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。(因此我们通常配合捕获列表使用

        ->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。

        {statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。

        例如,下面的代码定义了一个简单的 lambda 表达式,它接受两个整数参数并返回它们的和:

auto add = [](int a, int b) -> int {
    return a + b;
};//通常用auto来接收
std::cout << add(2, 3); // 输出 5

        注意:

        在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。

二、lambda表达式详解

        捕捉列表

        在 C++ 中,Lambda 表达式可以使用捕获列表来指定它如何访问在其外部作用域中的变量。捕获列表可以包含以下元素:

   [ ]表示不捕获任何变量

        [var]:表示值传递方式捕捉变量var

        [=]:表示值传递方式捕获所有父作用域中的变量(包括this) 

        [&var]:表示引用传递捕捉变量var

        [&]:表示引用传递捕捉所有父作用域中的变量(包括this)

        [this]:表示值传递方式捕捉当前的this指针 

注意:

a. 父作用域指包含lambda函数的语句块
b. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量[&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量
c. 捕捉列表不允许变量重复传递,否则就会导致编译错误。

比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复

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

e. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都会导致编译报错。

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

 [var]:表示值传递方式捕捉变量var

        需要注意的是传递过来的变量默认是const 的,是不能进行修改的,但是可以读。如果要修改需要用到外面的mutable。这里的传递实际上就是传值传参数初始化lambda函数。

如下例子:(这里未使用mutable)

	int x = 1, y = 2;
	auto cg = [x, y](){int tmp = x; x = y; y = tmp; };

C++lambda表达式,C++修仙 筑基中,c++,开发语言

 使用了mutable后:

int x = 1, y = 2;
auto cg = [x, y]()mutable{int tmp = x; x = y; y = tmp; };

C++lambda表达式,C++修仙 筑基中,c++,开发语言

        如上我们写了一个交换两值的数,但是由于只是传递值所以没有进行改变,意思就是函数里面的x和y和函数外的x和y不是同一个,这也是为什么这种捕捉也叫做:传值捕捉。

        如果我们要实现交换我们可以使用下面的传引用捕捉。

[&var]:表示引用传递捕捉变量var
int x = 1, y = 2;
auto cg = [&x, &y]()mutable{int tmp = x; x = y; y = tmp; };
//auto cg = [&x, &y](){int tmp = x; x = y; y = tmp; };
//两种都可用,都是符合要求的

C++lambda表达式,C++修仙 筑基中,c++,开发语言

C++lambda表达式,C++修仙 筑基中,c++,开发语言

[=]:表示值传递方式捕获所有父作用域中的变量(包括this) 
	int x = 3;
	char ss = 'Q';
	auto cg = [=]() {cout << x << ' ' << ss << endl; };

C++lambda表达式,C++修仙 筑基中,c++,开发语言

[&]:表示引用传递捕捉所有父作用域中的变量(包括this)
int x = 3;
char ss = 'Q';
auto cg = [&]() { x = 4; ss = 'U'; };

C++lambda表达式,C++修仙 筑基中,c++,开发语言

[this]:表示值传递方式捕捉当前的this指针 

        我们通常会在类中使用[this]来捕获父作用域中的变量,如果我们要使用成员变量,通常就需要捕获this,如果直接捕获是不会成功的,因为只能捕获 作用域中的变量。如下:

C++lambda表达式,C++修仙 筑基中,c++,开发语言

//正确的使用方法如下:用[this]捕获成员变量
class TX
{
public:
	void fun()
	{
		auto cg = [this]() {cout << a << " " << b << endl; };
		cg();
	}

private:
	int a=4;
	char b='U';
};

C++lambda表达式,C++修仙 筑基中,c++,开发语言

[=,&]:拷贝与引用混用

        拷贝与引用混用主要由于有特殊的值需要引用的原因,比如以下的例子:

[=,&val]混用

	int x = 0;
	int y = 10;
	string ss = "114514";
	auto cg = [=, &x, &y]() {cout << x << " " << y << " " << ss << endl; int tmp = x; x = y; y = tmp; };
	cg();
	cout <<x<<" "<<y<< endl;
//结果为:0 10 114514
//       10 0

[&,val]混用

	int x = 0;
	int y = 10;
	string ss = "114514";
	auto kg = [&,ss]() {cout << x << " " << y << " " << ss << endl; int tmp = x; x = y; y = tmp; };
	kg();
	cout << x << " " << y << endl;
//结果为:0 10 114514
//       10 0

        但是需要注意的是当我们已经捕获过变量而再次去捕获是不行的,比如[=,x]这样就重复的捕获了,同理[&,&x]也是不行的。同理的我们也可以混用[&,this]、[=,&a,&this]等。

        返回值类型

C++ lambda表达式的返回类型可以是任意类型,包括基本数据类型、引用类型、指针类型、数组类型、结构体类型、类类型等。

  1. 无返回值:[]() {}
  2. 一个返回值:[x]() { return x; }
  3. 多个返回值:[x, y]() { return std::make_pair(x, y); }
  4. 带有异常规范的返回值:[&]() noexcept { /*...*/ }
  5. 带有完美转发的返回值:[&]() -> T { /*...*/ }
  6. 带有默认参数的返回值:[x = 10, y]() -> int { return x + y; }
  7. 带有模板参数的返回值:[T](T t) -> decltype(t * t) { return t * t; }
  8. 带有捕获列表的返回值:[&]() -> int { /*...*/ }
  9. 带有命名捕获列表的返回值:[&a, &b]() -> int { /*...*/ }
  10. 带有初始化捕获列表的返回值:[&]() -> int { static int count = 0; return ++count; }

        需要注意的是:C++中Lambda的返回类型会自动推导。即:可以不使用->returntype,编译器会根据函数体中的return的类型进行推导。但是如果指定了返回类型,编译器则会根据指定的类型返回。

	auto ch = [](int x, int y)->double { return x + y; };
	auto ch2 = [](int x, int y){ return x + y; };
	cout <<ch(1,2) <<endl;
	cout << typeid(ch(1,2)).name() << endl;
    //结果为:3 double
	cout << ch2(1, 2) << endl;
	cout << typeid(ch2(1, 2)).name() << endl;
    //结果为:3 int

C++lambda表达式,C++修仙 筑基中,c++,开发语言

        其余部分

        (parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略 

        mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。(因此我们通常配合捕获列表使用

        {statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。 

三、lambda与仿函数的对比 

        函数对象,又称为仿函数,即可以想函数一样使用的对象,就是在类中重载了operator()运算符的类对象。而实际上从使用方式上来看,函数对象与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);
// lamber
auto r2 = [=](double monty, int year)->double{return monty*rate*year;
};
r2(10000, 2);
return 0;

        函数对象将rate作为其成员变量,在定义对象时给出初始值即可,lambda表达式通过捕获列表可以直接将该变量捕获到。

底层观察:

C++lambda表达式,C++修仙 筑基中,c++,开发语言

实际在底层编译器对于lambda表达式的处理方式,完全就是按照函数对象的方式处理的,即:如果定义了一个lambda表达式,编译器会自动生成一个类,在该类中重载了operator()。

lambda与仿函数的异同

        在C++中,lambda函数和仿函数都是用来创建匿名函数的方式。它们的共同点在于都可以在函数内部定义一些代码,并且这些代码可以在整个程序中重复使用。但是,它们也有一些重要的不同之处。

相同点:

1. **匿名性**:lambda函数和仿函数都是匿名的,也就是说它们没有名字,只有其函数体。

2. **可以被捕获**:lambda函数和仿函数都可以被捕获,这意味着它们可以访问其外部作用域中的变量。但是,lambda函数可以捕获任何类型的对象,而仿函数只能捕获引用。

3. **可以有参数**:lambda函数和仿函数都可以有参数。参数可以是任何类型的,也可以是有默认值的。

4. **可以有返回值**:lambda函数和仿函数都可以有返回值,而且可以是任何类型的。

5. **可以作为函数参数**:lambda函数和仿函数都可以作为其他函数的参数。

不同点:

1. **模板函数支持**:lambda函数可以直接作为模板函数的参数,而仿函数则不行。

2. **内联性能**:对于简单的、只有一行代码的函数,lambda函数通常比仿函数更快,因为它们不需要额外的函数调用开销。

3. **调用特性**:lambda函数可以提供更强大的调用特性,比如静态成员和虚函数的重载。

4. **定义方式**:lambda函数的定义方式更为简洁明了,而仿函数需要先声明再定义。

5. **适应范围**:lambda函数适合于简单的、一次性的函数,而仿函数适合于复杂的、需要复用的函数。

6. **捕获方式**:lambda函数可以通过多种方式捕获外部变量,如自动捕获、值捕获、引用捕获等,而仿函数只能通过引用捕获。

总的来说,lambda函数更适合于简单的、一次性的函数,而仿函数更适合于复杂的、需要复用的函数。同时,lambda函数的定义方式更为简洁明了,但是在使用时需要注意其内存管理和性能问题。


                          感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o! 

                                       C++lambda表达式,C++修仙 筑基中,c++,开发语言

                                                                         给个三连再走嘛~  文章来源地址https://www.toymoban.com/news/detail-778165.html

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

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

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

相关文章

  • .NET写一个自己的Lambda表达式与表达式树

    LambdaExpression继承Expression Expression 又继承LambdaExpressio 所以,LambdaExpression与 Expression 的区别在于:泛型类以静态类型的方法标识了它是什么种类的表达式,也就是说,他确定了返回类型和参数。所以显然,TDelegate必须是一个委托类型。 注意 :并非所有的Lambda表达式都能转换成

    2024年02月13日
    浏览(48)
  • 23.Lambda表达式

    Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。Lambda表达式是Java SE 8中一个重要的新特性。

    2024年02月03日
    浏览(45)
  • Lambda表达式(JAVA)

    注:如果没有学过 匿名内部类 和 接口 不推荐往下看。 (parameters) - expression 或 (parameters) -{ statements; } parameters:表示参数列表; -:可理解为“被用于”的意思; expression:表示一条语句; statements:表示多条语句。 Lambda可以理解为:Lambda就是匿名内部类的简化。 lambda表达式

    2024年02月08日
    浏览(54)
  • Java Lambda表达式

    1.1 函数式编程思想概括 在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿数据做操作” 面向对象思想强调“必须通过对象的形式来做事情” 函数式思想则尽量忽略面

    2024年02月07日
    浏览(61)
  • Java Lambda 表达式

    💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! Java Lambda 表达式是 Java 8 引入的一种函数式编程特性,它是一种轻量级的匿名函数,允许我们将函数作为方法的参数进行传递。Lambda 表达式可以理解为是一种简洁的方式来表示可传递的代码块,它可以替代传统的匿名内

    2024年02月08日
    浏览(55)
  • 深入理解lambda表达式

    var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.Use(async (context, next) = { // Add code before request. }); 这段C#代码是用于设置ASP.NET Core应用中的中间件。下面是详细解释: app.Use : 这个方法是用来向应用的请求处理管道中添加一个中间件的。在ASP.NET Core中,中间件用于处

    2024年02月20日
    浏览(48)
  • 9.4 Lambda表达式

    2024年01月22日
    浏览(49)
  • 什么是Lambda表达式?

    Lambda表达式是Java 8引入的一个重要特性,用于简化函数式编程中的匿名函数的定义和使用。它可以被视为一种轻量级的匿名函数,可以作为参数传递给方法或存储在变量中。 Lambda表达式的语法形式如下: 其中: parameters:表示方法的参数列表,可以是空的,或者包含一个或多

    2024年02月09日
    浏览(44)
  • Lambda表达式常用场景

    如果你的集合里泛型是ListString,那么可以直接用String.join(\\\",\\\",你的集合),把它变为字符串。 String.join(\\\",\\\", yourList) 但是如果你的集合是,ListInteger、ListLong,那么String.join这个方法就不适应了. 你可以用lamba表达式 String string= longs.stream().map(Object::toString).collect(Collectors.joining(\\\",\\\")); 方

    2024年02月11日
    浏览(44)
  • C#-Lambda 表达式

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 C# 中的lambda 表达式 Lambda表达式是一个匿名函数,基于数学中的λ演算得名。它是一个没有函数名的函数,可以直接表示闭包。Lambda表达式可以表示在数学传统意义上不同的闭包,因为它们具有定义域内

    2024年01月25日
    浏览(39)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包