C++11的lambda表达式
lambda来源于函数式编程的概念。C++11这次终于把lambda加进来了。
lambda表达式有如下优点:
1、声明式编程风格:就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象。以更直接的方式去写程序,好的可读性和可维护性。
2、简洁:不需要额外再写一个函数或者函数对象,避免了代码膨胀和功能分散,让开发者更加集中精力在手边的问题,同时也获取了更高的生产率。
3、在需要的时间和地点实现功能闭包,使程序更灵活。
lambda表达式的概念和基本用法
lambda表达式定义了一个匿名函数,并且可以捕获一定范围内的变量。lambda表达式的语法形式可简单归纳如下:
[capture](params) opt -> ret { body; };
其中:capture是捕获列表;params是参数表;opt是函数选项;ret是返回值类型;body是函数体。
因此,一个完整的lambda表达式看起来像这样:
auto f = [](int) -> int { return a + 1;};cout << f(1) << endl; //输出:2
可以看到,上面通过一行代码定义了一个小小闭包,用来输入加1并返回。
在C++11中,lambda表达式的返回值是通过前面介绍的返回值后置语法来定义的。其实很多时候,lambda表达式的返回值是非常明显的,比如上例。因此,C++11中运行省略lambda表达式的返回值定义:
auto f = [](int a) {return a + 1; };
这样编译器就会根据return语句自动推导出返回值类型。
需要注意的是,初始化列表不能用于返回值的自动推导。
auto x1 = [](int i){ return i; }; //OK:return type is intauto x2 = [](){ return {1, 2};}; // error:无法推导出返回值类型
这时我们需要显示给出具体的返回值类型。
另外,lambda表达式在没有参数列表时,参数列表是可以省略的。因此像下面的写法都是正确的:
auto f1 = [] () { return 1; };auto f2 = [] { return 1; }; //省略空参数表
lambda表达式可以通过捕获列表捕获一定范围的变量:
1、[]不捕获任何变量。
2、[&]捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
3、[=]捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。
4、[=, &foo]按值捕获外部作用域中所有变量,并按引用捕获foo变量。
5、[bar]按值捕获bar变量,同时不捕获其他变量。
6、[this]捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限。如果已经使用了&或者=,就默认添加此选项。捕获this的目的是可以在lambda中使用当前类的成员函数和成员变量。
lambda表达式基本用法
#include <iostream>
using namespace std;class A
{
public:int i_ = 0;void func(int x, int y){///auto x1 = [] { return _i; }; ///error,没有捕获外部变量auto x2 = [=] { return i_ + x + y; }; ///OK,捕获所有外部变量auto x3 = [&] { return i_ + x + y; }; ///OK,捕获所有外部变量auto x4 = [this] { return i_; }; ///OK,捕获this指针///auto x5 = [this] { return i_ + x + y; }; ///error,没有捕获x,yauto x6 = [this, x, y] { return i_ + x + y; }; ///OK,捕获this指针,x,yauto x7 = [this]{ return i_ ++; }; ///OK,捕获this指针,并修改成员的值}};int main()
{int a = 0, b = 1;auto f1 = [] { return a; }; ///error,没有捕获外部变量auto f2 = [&] { return a++; }; ///OK,捕获所有外部变量,并对a执行自加运算auto f3 = [=] { return a; }; ///OK,捕获所有外部变量,并返回aauto f4 = [=] { return a++; }; ///error,a是以复制方式捕获的,无法修改auto f5 = [a] { return a + b; }; ///error,没有捕获变量bauto f6 = [a, &b] { return a + (b++); }; ///OK,捕获a和b的引用,并对b做自加运算auto f7 = [=, &b] { return a + (b++); }; ///OK,捕获所有外部变量和b的引用,并对b做自加运算return 0;
}
从上例中可以看到,lambda表达式的捕获列表精细的控制了lambda表达式能够访问的外部变量,以及如何访问这些变量。
需要注意的是,默认状态下lambda表达式无法修改通过复制方式捕获的外部变量。如果希望修改这些变量的话,我们需要使用引用方式进行捕获。
int a = 0;auto f = [=] { return a; };a += 1;cout << f() << endl;
在这个例子中,lambda表达式按值捕获了所有外部变量。在捕获的一瞬间,a的值就已经被复制到f中了。之后a被修改了,但此时f中存储的a仍然还是捕获时的值,因此,最终输出结果是0。
如果希望lambda表达式在调用时能够及时访问外部变量,我们应当使用引用方式捕获。
如果希望去修改按值捕获的外部变量,需要显示指明lambda表达式为mutable:
int main()
{int a = 0;///auto f1 = [=](){ return a++; }; ///error,修改按值捕获的外部变量auto f2 = [=]()mutable { return a++; }; ///OK,mutablereturn 0;
}
需要注意的一点是,被mutable修改的lambda表达式就算没有参数也要写明参数列表。
lambda表达式的类型在C++11中被称为“闭包类型”。它是一个特殊的,匿名的非nunion的类型。因此,我们可以认为它是一个带有operator()的类,即仿函数。因此,我们可以使用std::function和std::bind来存储和操作lambda表达式:
std::function<int(int)> f1 = [] (int a) { return a; };
std::function<int(void)> f2 = std::bind( [] (int a) { return a; }, 123);
另外,对于没有捕获任何变量的lambda表达式,还可以被转换成一个普通的函数指针:
using func_t = int(*)(int);
func_t f = [] (int a) { return a; };
f(123);
lambda表达式可以说是就地定义仿函数闭包的“语法糖”。它的捕获列表捕获住的任何外部变量,最终均会变成闭包类型的成员变量。而一个使用了成员变量的类的operator(),如果能直接被转换为普通的函数指针,那么lambda表达式本身的this指针就会丢失掉。而没有捕获任何外部变量的lambda表达式则不存在这个问题。
这里也可以很自然的解释为何按值捕获无法修改捕获的外部变量。因为按照C++标志,lambda表达式的operator()默认是const的。一个const成员函数是无法修改成员变量的值的。而mutable的作用,就在于取消operator()的const。
声明式的编程风格,简洁的代码
就地定义匿名函数,不再需要定义函数对象,大大简化了标准库算法的调用。在C++11之前,我们要调用for_each函数将vector中的偶数打印出来,代码如下所示:
#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;class CountEven
{
public:CountEven(int& c):count(c){}void operator()(int val){if (!(val & 1)){++count;}}private:int& count;
};int main()
{int count = 0;vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};for_each(v.begin(), v.end(), CountEven(count));cout << "The number of even is " << count << endl;return 0;
}
这样写既繁琐又容易出错。有了lambda表达式以后,我们可以使用真正的闭包概念来替换这里的仿函数,代码如下所示:
#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;class CountEven
{
public:CountEven(int& c):count(c){}void operator()(int val){if (!(val & 1)){++count;}}private:int& count;
};int main()
{int count = 0;vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};for_each(v.begin(), v.end(), CountEven(count));cout << "The number of even is " << count << endl;count = 0;for_each(v.begin(), v.end(), [&count](int val){if (!(val & 1)){++ count;}});cout << "The number of even is " << count << endl;return 0;
}
lambda表达式的价值在于,就地封装短小的功能闭包,可以及其方便的表达出我们希望执行的具体操作,并让上下文结合得更加紧密。
相关文章:
C++11的lambda表达式
lambda来源于函数式编程的概念。C11这次终于把lambda加进来了。 lambda表达式有如下优点: 1、声明式编程风格:就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象。以更直接的方式去写程序,好的可读性和可维护…...

矩阵特征值与特征向量的理解
各位朋友大家好,我是小C哈哈哈,很高兴认识大家,在这里,我会将一些枯燥难懂的数学和算法知识以图片或动画的形式通俗易懂的展现给大家,希望大家喜欢。 线性代数中的矩阵特征值与特征向量这两个基本概念总是让很多人摸不…...

云原生安全:如何保护云上应用不受攻击
文章目录 云原生安全的概念1. 多层次的安全性2. 自动化安全3. 容器安全4. 持续监控5. 合规性 云原生安全的关键挑战1. 无边界的环境2. 动态性3. 多云环境4. 容器化应用程序5. API和微服务 如何保护云上应用不受攻击1. 身份验证和访问控制示例代码: 2. 数据加密示例代…...

如何在用pip配置文件设置HTTP爬虫IP
首先,定义问题:在 Pip 中设置HTTP爬虫IP服务器,以便在网络上进行访问和下载。 亲身经验:我曾经遇到过类似问题,通过设置HTTP爬虫IP服务器成功解决了网络访问问题。 数据和引证:根据 pip 官方文档ÿ…...

2023MathorCup高校数模挑战赛B题完整解题代码教程
赛道 B: 电商零售商家需求预测及库存优化问题 问题背景: 电商平台存在着上千个商家,他们会将商品货物放在电商配套的仓库, 电商平台会对这些货物进行统一管理。通过科学的管理手段和智能决策, 大数据智能驱动的供应链…...

《动手学深度学习 Pytorch版》 10.7 Transformer
自注意力同时具有并行计算和最短的最大路径长度这两个优势。Transformer 模型完全基于注意力机制,没有任何卷积层或循环神经网络层。尽管 Transformer 最初是应用于在文本数据上的序列到序列学习,但现在已经推广到各种现代的深度学习中,例如语…...

ORACLE-递归查询、树操作
1. 数据准备 -- 测试数据准备 DROP TABLE untifa_test;CREATE TABLE untifa_test(child_id NUMBER(10) NOT NULL, --子idtitle VARCHAR2(50), --标题relation_type VARCHAR(10) --关系,parent_id NUMBER(10) --父id );insert into untifa_test (CHILD_ID, TITLE, RELATION_TYP…...
MySQL篇---第四篇
系列文章目录 文章目录 系列文章目录一、并发事务带来哪些问题?二、事务隔离级别有哪些?MySQL的默认隔离级别是?三、大表如何优化?一、并发事务带来哪些问题? 在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对 同一数据进行操作…...
em/px/rem/vh/vw单位的区别
一、绝对长度单位 1.px 表示像素,显示器上每个像素点大小都是相同的 二、相对长度单位 2.em 相对于当前对象内文本的字体尺寸,如未设置对行内文本字体的尺寸,则相对于浏览器的默认字体(1em16px) em值不是固定的&…...

【C++】多态 ③ ( “ 多态 “ 实现需要满足的三个条件 | “ 多态 “ 的应用场景 | “ 多态 “ 的思想 | “ 多态 “ 代码示例 )
文章目录 一、" 多态 " 实现条件1、" 多态 " 实现需要满足的三个条件2、" 多态 " 的应用场景3、" 多态 " 的思想 二、" 多态 " 代码示例 一、" 多态 " 实现条件 1、" 多态 " 实现需要满足的三个条件 &q…...

创建一个Keil项目
1、创建项目 2、选择存放的文件夹,还有设置项目名 3、选择型号(因为没有STC,用下面这个替代,功能差不多) 4、选择不用启动文件 5、就会得到下面这个,可以在Source Group 1下面编写代码了 6、右键source Group 1,添加c语…...

Xray的简单使用
xray 简介 xray 是一款功能强大的安全评估工具,由多名经验丰富的一线安全从业者呕心打造而成,主要特性有: 检测速度快。发包速度快; 漏洞检测算法效率高。支持范围广。大至 OWASP Top 10 通用漏洞检测,小至各种 CMS 框架 POC,均…...
Linux Ubunto Nginx安装
一 安装前 环境准备 gcc $ sudo apt-get install gcc zlib $ sudo apt-get install zlib1g-dev pcre $ sudo apt-get install libpcre3 libpcre3-dev openssl $ sudo apt-get install openssl libssl-dev‘ ubuntu 安装 libssl-dev失败的解决方案 1.安装aptitude sudo apt-g…...
深度学习中的epoch, batch 和 iteration
名词定义epoch使用训练集的全部数据进行一次完整的训练,称为“一代训练”batch使用训练集中的一小部分样本对模型权重进行一次反向传播的参数更新,这样的一部分样本称为:“一批数据”iteration使用一个batch的数据对模型进行一次参数更新的过…...
unity开发安卓视频文件适配手机和平板
using UnityEngine; using UnityEngine.UI;public class VideoResize : MonoBehaviour {private RawImage rawImage;private VideoPlayer videoPlayer;private void Start(){rawImage GetComponent<RawImage();videoPlayer GetComponent<VideoPlayer>();// 播放视频…...
NLP之RNN的原理讲解(python示例)
目录 代码示例代码解读知识点介绍 代码示例 import numpy as np import tensorflow as tf from tensorflow.keras.layers import SimpleRNNCell# 第t时刻要训练的数据 xt tf.Variable(np.random.randint(2, 3, size[1, 1]), dtypetf.float32) print(xt) # https://www.cnblog…...

yo!这里是进程间通信
目录 前言 进程间通信简介 目的 分类 匿名通道 介绍 举例(进程池) 命名管道 介绍 举例 共享内存 介绍 共享内存函数 1.shmget 2.shmat 3.shmdt 4.shmctl 举例 1.框架 2.通信逻辑 消息队列 信号量 同步与互斥 理解信号量 后记…...
使用docker安装MySQL,Redis,Nacos,Consul教程
文章目录 安装MySQL安装Redis安装Nacos安装Consul 如未安装docker,参考教程: https://blog.csdn.net/m0_63230155/article/details/134090090 安装MySQL #拉取镜像 sudo docker pull mysql:latestsudo docker run --name mysql \-p 3306:3306 \-e MYSQ…...
python和Springboot如何交互?
Python和Spring Boot可以通过RESTful API进行交互。Spring Boot通常用于后端开发,提供了快速构建RESTful API的工具,而Python则可以用于编写前端或与后端交互的代码。 要实现Python和Spring Boot的交互,可以按照以下步骤进行: 在…...
Qt实现json解析
前提要点 json文件,可通过键值的方式存储你所需要的数据,斌且支持多种类型存储,类似于一种结构化的数据库,在读取json文件时可通过相对应的关键字精准获取。他是一种树状结构,我们可以自己设定叶子的数量以及他所代表…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...