c++11 lambda函数

lambda历史悠久,在数理逻辑和计算机科学领域,lambda被用来表示一种匿名函数这种匿名函数代表了一种λ演算(lambda calculus),但是在c++领域直到c++11才引入lambda表达式,本文先打算从lambda函数入手、后续会继续从lambda与仿函数、lambda基础应用、lambda的实验以及lambda与STL关系等5个方面来阐述一下c++11新特性lambda表达式

一、lambda函数
先看一个例子来直观地感受一下lambda函数

#include<iostream>

using namespace std;

int main()
{
  int salary = 8000,expense = 5000;
  auto surplus = [](int salary,int expense)->int{return salary-expense;};
  cout<<surplus(salary,expense)<<endl;
  return 0;
}

功能:lambda函数接收两个参数(int,int),并返回两者之差。
结构:与普通函数相比没有函数名,取而代之的是一对方括号,此外返回值是采用返回类型追踪的方式声明。

lambda函数的语法定义如下:

  • [capture](paramters) mutable->return-type{statement}

  • [capture}:捕捉列表。[]是lambda引出符。编译器根据该引出符判断接下来的代码是否是lambda函数。捕捉列表能够捕捉上下文的变量供lambda函数使用。

  • [parameters]:参数列表,与普通函数参数列表一样

  • mutable:mutable修饰符。默认情况下lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符的时候参数列表不可省略(即使参数为空)

  • ->retrurn-type:返回值类型,不需要返回值的地方可以连同->一起省略,在返回值类型明确的情况下,也可以省略该部分,让编译器自己推导。

  • {statement}:函数体。内容和普通函数一样,不过除了可以使用参数之外还可以使用所有捕获的变量。

    所以最简单的lambda表达式可以写成 []{} ,当然此函数啥都干不了。。。

对于捕捉列表的使用是lambda表达式与普通函数最大的区别之一,就是lambda函数可以通过捕捉列表访问一些上下文的数据。具体地,捕捉列表描述了上下文中哪些的数据可以被lambda使用,以及使用方法(值传递、引用传递),上个例子中我们使用了参数的方法传递变量,现在我们使用捕捉变量来改写这个例子。

#include<iostream>

using namespace std;

int main()
{
  int salary = 8000,expense = 5000;
  auto surplus = [salary,expense]()->int{return salary-expense;};   //salary和expense被lambda函数捕获,参数列表就可以省略
  cout<<surplus()<<endl;
  return 0;
}

此时salary和expense可以视为函数的一种初始状态,lambda函数则是基于初始状态进行的运算,这与函数简单基于参数的运算是不同的。
当然了,捕获和参数列表可以同时存在,即捕获又传参

#include<iostream>

using namespace std;

int main()
{
  int salary = 8000,expense = 5000,tmp = 1;
  auto surplus = [salary,expense](int tmp )->int{return salary-expense;};
  cout<<surplus(tmp )<<endl;
  return 0;
}

**语法上,捕捉列表由多个捕捉项组成,并以逗号分隔。捕捉列表主要有如下几种形式:

  • [var]表示值传递方式捕获变量var //如 auto surplus = salary,expense->int{return
    salary-expense;};
  • [=]表示值传递方式捕捉所有父定义域的变量(包括this) //如 [=]{return a+b;};
  • [&var]表示引用传递捕获变量var //如 [&a]{return a+b;};
  • [&]表示引用传递捕获父作用域 //如 [&]{return a+b;};
  • [this]表示值传递方式捕获当前的this指针 //如 [this]{int a = this->…};**

但是要注意想要在mutbale在引用传递和值传递上的区别

#include<iostream>

using namespace std;

int main()
{
  int salary = 8000,expense = 5000;
  auto surplus = [=](int salary,int expense)  ->int{salary = 10000; return salary-expense;};
  cout<<"salary:"<<salary<<endl;
  cout<<"surplus:"<<surplus(salary,expense)<<endl;
  return 0;
}

运行结果如下:
salary:8000
surplus:5000
这个例子有一定迷惑性,也是博主随手写成这样了,才发现的问题,因为是值传递,其实[=]值传递过去的父空间的salary和expense没有在lambda表达式内用到,而采用就近原则用的是参数列表(int salary,int expense)在下面调用的时候的参数传递的值。
言归正传,看一下mutable

#include<iostream>

using namespace std;

int main()
{
  int salary = 8000,expense = 5000;
  auto surplus = [=]()  ->int{salary = 10000; return salary-expense;};
  cout<<"salary:"<<salary<<endl;
  cout<<"surplus:"<<surplus()<<endl;
  return 0;
}

编译报错如下:
在这里插入图片描述
因为lambda函数默认是const函数,所以要修改需要加上mutable(可修改的),如下:

#include<iostream>

using namespace std;

int main()
{
  int salary = 8000, expense = 5000;
  auto surplus = [=]() mutable ->int {salary = 10000; return salary - expense; };
  cout << "salary:" << salary << endl;
  cout << "surplus:" << surplus() << endl;
  return 0;
}

运行结果:
在这里插入图片描述
再来看一下引用传递有啥区别

#include<iostream>

using namespace std;

int main()
{
  int salary = 8000, expense = 5000;
  auto surplus = [&]() ->int {salary = 10000; return salary - expense; };
  cout << "salary:" << salary << endl;
  cout << "surplus:" << surplus() << endl;
  return 0;
}

运行结果:
在这里插入图片描述
结果看出引用传递是否加mutable都是可以修改的,但是有个需要注意的地方,按照一般函数的理解,引用是要被修改了的,但是这边的salary还是一开始的8000,而不是10000,所以说明不论是值传递还是引用传递,传递进去的值对父空间原值无影响。&与mutable的测试就不在赘述了
注意点:
[=,&] 这种写法‘=’已经以值传递的方法捕捉过所有的父作用域的变量,&再去捕捉的时候就会报错

在这里插入图片描述

人,总是要有一点精神的,不是吗

发布了32 篇原创文章 · 获赞 23 · 访问量 878

猜你喜欢

转载自blog.csdn.net/weixin_40179091/article/details/104982289
今日推荐