C++11 lambda表达式(下)

简介: C++11 lambda表达式(下)

lambda表达式交换两个数

标准写法

  int a = 10;
  int b = 20;
  auto swap = [](int& x, int& y)->void
  {
    int z = x;
    x = y;
    y = z;
  };
  swap(a, b);
  • 因为lambda表达式是一种匿名函数 所以无法直接调用 如果想要调用 我们可以借助auto关键字将其赋值给一个变量 用该变量来实现功能
  • lambda表达式的函数体在格式上并不是必须写成一行 如果函数体太长可以进行换行 但换行后不要忘了函数体最后还有一个分号

利用捕获列表进行捕捉


以引用的方式捕捉所有父作用域中的变量 省略参数列表和返回值类型 比如:

  int a = 10;
  int b = 20;
  auto swap = [&a, &b] // (使用 & 捕获所有参数的引用也可以)
  {
    int z = a;
    a = b;
    b = z;
  };
  swap(); // 我们这里还必须要调用以下这个函数才会使用

传值捕捉

因为我们的lambda函数默认是具有常属性的 它不会修改内部对象的值

所以说如果我们使用值传参的话编译器是会报错的 像下面这样子

3cac33cf24f64f2d9d1a3493ecdd4777.png

所以说我们要先使用mutable关键字省略其常属性 但是省略了这个属性之后参数列表就不能省略了

  int a = 10;
  int b = 20;
  auto swap = [=]()mutable // (使用 & 捕获所有参数的引用也可以)
  {
    int z = a;
    a = b;
    b = z;
  };
  swap(); // 我们这里还必须要调用以下这个函数才会使用

但是传值传递本质上是对于原始数据的一份临时拷贝 它的修改并不会改变原始的数据 所以说调用了swap函数也不会发生什么


lambda表达式的底层原理

lambda表达式的底层原理

实际编译器在底层对于lambda表达式的处理方式 完全就是按照函数对象的方式处理的 函数对象就是我们平常所说的仿函数 就是在类中对()运算符进行了重载的类对象

我们下面实现一个对象 对于其()运算符进行重载

之后再编写一个lambda表达式 使用函数的方式来调用之

代码如下

class Add
{
public:
  Add(int base)
    :_base(base)
  {}
  int operator()(int num)
  {
    return _base + num;
  }
private:
  int _base;
};
int main()
{
  int base = 1;
  //函数对象
  Add add1(base);
  add1(1000);
  //lambda表达式
  auto add2 = [base](int num)->int
  {
    return base + num;
  };
  add2(1000);
  return 0;
}

我们这里实现了一个add函数 它有一个_base的私有成员变量 并且我们重载了它的()运算符

另外我们还实现了一个lambda表达式 为了更加深入的了解底层 我们调试之后进入反汇编看看汇编代码式什么样子的

ec06ac79a18d48d0aa63b960a9cf5cbc.png

  • 我们可以看到 在创建add1的时候使用Add类的构造对象
  • 在再使用时会调用operator()操作符

de3ba6f48f514900a39d510071d1a3bd.png

  • 我们可以看到 在创建add2的时候使用‘main’类构造对象
  • 而在使用时会调用operator()操作符


这里的本质原因是因为为lambda表达式在底层被转换成了仿函数

当我们定义一个lambda表达式后 编译器会自动生成一个类 在该类中对()运算符进行重载 实际lambda函数体的实现就是这个仿函数的operator()的实现

在调用lambda表达式时 参数列表和捕获列表的参数 最终都传递给了仿函数的operator()


lambda表达式之间不能相互赋值

lambda表达式之间是不能相互赋值的 就算它们的语法层面一模一样


原因如下

因为lambda表达式在底层的处理方式和仿函数一样 在创建的时候它会被定义为一个类 类名叫做 <lambda_uuid>

类名中的uuid叫做唯一标识码(Universally Unique Identifier) 简单来说uuid就是通过算法生成一串在当前程序中唯一的不会重复的字符串

lambda表达式底层的类名包含uuid 所以说每个类都是独一无二的


我们这里可以用下面的一段代码和其运行结果证明之

int main()
{
  int a = 10, b = 20;
  auto Swap1 = [](int& x, int& y)->void
  {
    int tmp = x;
    x = y;
    y = tmp;
  };
  auto Swap2 = [](int& x, int& y)->void
  {
    int tmp = x;
    x = y;
    y = tmp;
  };
  cout << typeid(Swap1).name() << endl; 
  cout << typeid(Swap2).name() << endl; 
  return 0;
}

cf57d3e44d024fe092e4c6549a94d662.png

相关文章
|
1月前
|
编译器 C++
C++系列七:表达式
C++系列七:表达式
|
1月前
|
算法 编译器 C++
【C++】—— c++11新特性之 lambda
【C++】—— c++11新特性之 lambda
|
17天前
|
编译器 C语言 C++
C++ lambda表达式
C++ lambda表达式
|
1月前
|
算法 安全 编译器
【C++ 17 新特性 折叠表达式 fold expressions】理解学习 C++ 17 折叠表达式 的用法
【C++ 17 新特性 折叠表达式 fold expressions】理解学习 C++ 17 折叠表达式 的用法
24 1
|
1月前
|
算法 程序员 编译器
C ++匿名函数:揭开C++ Lambda表达式的神秘面纱
C ++匿名函数:揭开C++ Lambda表达式的神秘面纱
59 0
|
1月前
|
存储 JavaScript 前端开发
c++lambda函数与表达式
c++lambda函数与表达式
9 1
|
2月前
|
C++
【c++】定位new表达式(placement-new)
【c++】定位new表达式(placement-new)
【c++】定位new表达式(placement-new)
|
2月前
|
存储 算法 编译器
C++ 新特性 lamada表达式
C++ 新特性 lamada表达式
|
2月前
|
安全 C++ 开发者
c++表达式详细介绍
前言 表达式是 C++ 语言的基石之一,它们在程序中执行计算、赋值、逻辑判断和更多操作。本文旨在提供对 C++ 表达式各个方面的全面了解,包括基础概念、类型、求值规则以及高级主题。
68 0
|
3月前
|
Java C++ Python
C/C++每日一练(20230422) 存在重复元素、组合总和、给表达式添加运算符
C/C++每日一练(20230422) 存在重复元素、组合总和、给表达式添加运算符
30 0
C/C++每日一练(20230422) 存在重复元素、组合总和、给表达式添加运算符