当前位置: 首页 > news >正文

【C++11入门】新特性总结之lambda表达式

现代C++语言的核心特征之一:lambda表达式。虽然其它编程语言早已具备了这种特性,但直到C++11标准发布,C++11才具备了lambda表达式。本节主要讲解lambda表达式的语法和使用方法。具体包括:捕获列表、可选参数列表、可选异常说明符、可选返回值类型等。此外,还将介绍lambda表达式在STL算法中的应用和泛型lambda表达式的使用方法。

函数对象:

不过在此之前我们先来了解一下函数对象(仿函数)。函数对象其实就是在类内对函数调用运算符:()进行重载。因为使用方法与函数类似,我们又将其称为仿函数。

struct MyAdd{
public:int operator()(int a,int b){return a+b;}
};
class MyCompare{
public:bool operator()(int a,int b){return a<b;}
};

写两端的目的是为了告诉大家,C++中的struct和class都可以重载运算符来进行运算,一般我们又将返回值为bool的函数对象称为谓词,参数为一个就是一元谓词,参数为两个就是二元谓词

 那么我们知道函数对象又称仿函数,那么使用方法我们就可以猜出来了:

void test01(){MyAdd add;cout<<add(1,3)<<endl;//输出4
}
void test02(){MyCompare compare;cout<<compare(2,5)<<endl;//true--实际输出1
}

仿函数是C++中用于实现功能对象的两种重要机制之一,另一个就是lambda表达式。C++中的lambda表达式的底层与仿函数类似。lambda表达式可以定义匿名函数。优点在于简洁、可以捕获作用域中的变量,使得可以在函数内部使用外部变量。


基本语法:

[capture](parameters) -> return_type { body }

基本的lambda表达式的语法如上。其中:

capture:捕获外部变量的方式。

parameters:匿名函数的参数列表。

return_type:返回类型,通常可以省略,编译器会进行推导。

body:lambda表达式的函数体。 

捕获列表:

捕获列表指定了lambda表达式可访问的变量,并包括以下几种方式:

值捕获:复制外部变量的值到lambda中。

int x=10;
auto lambda = [x](){return x+5;}; //用值传递

引用捕获:捕获外部变量的引用,可以在lambda中修改变量。 

int x = 10;  
auto lambda = [&x]() { x += 5; }; // x 通过引用捕获

 默认捕获:[=]:值捕获所有外部变量,[&]:引用捕获所有外部变量。

int a = 5, b = 10;  
auto lambda = [=]() { return a + b; }; // 所有变量以值捕获
auto lambda = [&]() { return a + b; }; // 所有变量以引用捕获

 混合捕获:可以混合使用值和引用捕获。

int x = 1, y = 2;  
auto lambda = [x, &y]() { return x + y++; }; // x 值捕获,y 引用捕获

在这里大家肯定有点疑惑,捕获列表的用途是什么, 这有什么用,还没有看明白。这里我举个例子:

int main(){int a=10,b=20,c=30;char ch1='a',ch2=’B‘;//然后我想让ch1=a+b+c;但是过了本行不影响ch1的值return 0;
}

我想通过函数的方式调用,有很多方式,但大都是外部定义一个函数,但这时候,我们需要传入参数,变量多的时候,我们还要传很多的参数,定义普通的函数显然有点不合适。那么lambda表达式就很合适了,直接捕获所有变量,然后想使用啥使用啥,我眼中的lambda表达式其实是一种函数内部的匿名函数。 

参数和返回值:

参数:参数可以为空,也可以包含一个或多个参数,就像普通函数一样。

auto lambda = [](int a, int b) { return a + b; };

返回类型:如果返回类型明确、显式,可以调用->来指明返回类型,如果省略,编译器会自行推导。

底层探究: 

但凡是个表达式,都有其类型,那么lambda表达式是个什么类型呢?我们使用typeid().name()来输出一下看看。

这时候我们可以看出来lambda表达式的类型本身是一个类类型。每创立一个表达式,都会创建一个类,而且是在函数内部的作用域下创建的类,我们也可以看出来,每个lambda的类型都是不一样的。这时候我们想到了仿函数,仿函数是在类内重载了()运算符,那这个lambda表达式到底与仿函数有什么渊源呢?

 通过观察上面的反汇编语言。我们可以看出来,lambda的底层机制还是仿函数。只不过编译器会自动为你的lambda表达式生成一个类,将lambda表达式当作函数使用时其实就是调用类内的()重载函数。

STL算法应用:

Lambda 表达式经常与标准模板库(STL)的算法结合使用:

#include <vector>  
#include <algorithm>  
#include <iostream>  int main() {  std::vector<int> vec = {1, 2, 3, 4, 5};  std::for_each(vec.begin(), vec.end(), [](int &n) { n *= 2; });  //这里我们可以使用仿函数,也可以使用函数指针,也可以像本例一样使用lambda表达式for (const auto &n : vec) {  std::cout << n << " "; // 输出: 2 4 6 8 10  }  return 0;  
}
  • 简洁性: 不需要定义完整的函数,提高了代码的可读性。
  • 访问外部作用域: 可以直接使用外部的变量,而无需将其作为参数传递。
  • 灵活性: 可以在需要时快速定义函数,特别适用于 STL 算法。

注意事项:

  • Lambda 表达式在多线程环境下使用时要注意捕获对象的生命周期。
  • 当捕获的对象超出了作用域或被销毁后,如果 Lambda 仍然存在并使用这些对象,会导致未定义行为。

感谢大家!


http://www.mrgr.cn/news/51792.html

相关文章:

  • 人机之间的系统论不同于机器之间的系统论
  • 关于jmeter中没有jp@gc - response times over time
  • 华为OD机试真题---选修课
  • 分享一个图片RGB以及16进制颜色提取的在线网站
  • js高级-理解call()的原理
  • 【MySQL】入门篇—基本数据类型:使用ORDER BY进行排序
  • 【分布式微服务云原生】《Redis 缓存污染问题全解析及淘汰策略深度探索》
  • 1015邮件定时发送作业
  • Python库numpy之三
  • CCleaner Pro v6.29.11342 系统清理优化软件绿色便携版
  • PyQt入门指南十八 QSpinBox和QDoubleSpinBox微调框组件
  • 冒泡排序.
  • QCOM-Tools 高通工具QXDM、QCAT和QPST的使用
  • AI大模型带来哪些创业机遇?
  • 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-16
  • 重构长方法之以方法对象取代方法
  • 爬虫逆向
  • 数据结构:数字统计
  • 【分布式微服务云原生】《Redis 数据持久化与高可用高并发实战指南》
  • python 日志库loguru