【C++】lambda 表达式 / 包装器 / bind 绑定

目录

  • 一. lambda 表达式
    • 1. lambda 表达式的语法
    • 1. lambda 表达式的使用
    • 2. lambda 表达式的捕捉列表
  • 二. 包装器
  • 三. bind 绑定

一. lambda 表达式

Lambda 表达式是 C++11 标准引入的一种新特性, 它提供了一种方便的方式来定义匿名函数.

lambda 表达式实际上是一个匿名的仿函数; 不同于仿函数的是, 该类由编译器自动创建. 而调用lambda 表达式就相当于调用类的 operator() 函数.

1. lambda 表达式的语法

//    捕捉列表           参数列表					  返回值类型	       函数体
[/*capture-list*/] (/*parameters*/) mutable -> /*return_type*/ {/*statement*/};
  • [ ]: capture-list 捕捉列表, 该列表总是出现在 lambda 函数的开始位置, 编译器根据 [] 来判断接下来的代码是否为 lambda 函数, 捕捉列表能够捕捉上下文中的变量供 lambda 函数使用; 捕捉列表不可省略, 但可以为空.

  • ( ): parameters 参数列表, 与普通函数的参数列表一致, 若不需要参数传递, 则可以连同 () 一起省略, 但通常不建议省略.

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

  • ->: 后面接 return_type 返回值类型, 若没有返回值或返回值类型明确的情况下可以省略, 由编译器对返回类型自动推导.

  • { }: statement 函数体, 和普通函数的函数体一样, 不过在该函数体内, 除了可以使用其参数外, 还可以使用被 [ ] 所捕获的变量.

  • : 捕捉列表 [ ] 和 函数体 { } 不可省略; 若使用了 mutable 关键字 或 显示声明 -> return 返回值, 就不可以省略 ( ) 参数列表, 即使为空.

1. lambda 表达式的使用

lambda 表达式的类型是由编译器自动生成的, 并且带有随机值, 是无法具体的写出 lambda 表达式的类型, 并且 lambda 表达式是一个匿名的函数对象(匿名对象生命周期只有一行), 若不立即使用 或 使用 auto 推导赋值给对象, 则会销毁.

int main()
{// 						  显示声明返回值int ret = [](int i, int j)->int { return i + j; }(1, 2);cout << ret << endl;// 自动推导返回值auto add = [](int i, int j) { return i + j; };cout << add(1, 2) << endl;return 0;	
}

在这里插入图片描述

2. lambda 表达式的捕捉列表

lambda 表达式的使用相较于普通函数和仿函数, 增加了捕捉列表;
捕捉列表可以使 lambda 表达式捕捉父作用域中 lambda 表达式之前的所有变量.

  • 传值捕捉 [var]
    捕捉变量 var 的拷贝, 传值捕捉到的参数默认是被 const 修饰的, 若希望修改, 需要使用 mutable 修饰.
int main()
{int i = 1;auto add = [i](int j)mutable{ i = j;return i;};cout << add(2) << endl;return 0;	
}

在这里插入图片描述

在这里插入图片描述

  • 传引用捕捉 [&var]
    捕捉变量 var 的引用
    在这里插入图片描述
  • 传值捕捉所有 [=]
    捕捉所有变量的引用
    在这里插入图片描述
  • 传值捕捉所有 [&]
    捕捉所有变量的拷贝
    在这里插入图片描述
  • 混合捕捉
    捕捉所有(或部分)变量的拷贝(或引用)
    在这里插入图片描述

注:

  • 父作用域是指包含 lambda 函数的语句块, 捕捉列表可以捕捉父作用域中位于 lambda 函数之前定义的所有变量;
  • lambda 表达式的捕捉列表不允许变量重复传递, 否则就会导致编译错误;
  • 在块作用域中的lambda函数仅能捕捉父作用域中的局部变量, 捕捉任何非此作用域或者非局部变量都会导致编译报错;
  • lambda 表达式之间不能相互赋值.

二. 包装器

包装器是一种特殊的类模板, 是适配器的一种, 可以将相同或类似使用方式, 但类型不同的对象, 包装为同一类型, 使其可以达到类似回调函数的效果.

例:
下列的函数, 仿函数, lambda 表达式的使用方式相同, 但却会实例化出不同类型的 useF() 函数.

void func(int i) 
{i++;
}struct Functor 
{void operator()(int i){i++;}
};template<class F>
void useF(F f, int i) 
{static int count = 0;cout << "count:" << ++count << endl;cout << "count:" << &count << endl;f(i);
}int main()
{int i = 0;// 函数指针useF(func, i);// 仿函数useF(Functor(), i);// lambda 表达式useF([](int i) { i++; }, i);return 0;
}

在这里插入图片描述
C++11 中增加了 function 包装器解决了这类问题, function 包装器是使用可变参数模板实现的.

#include <functional>
// 类模板原型
template <class Ret, class... Args>	//Ret 被调用函数的返回类型, Args… 被调用函数的形参
class function<Ret(Args...)>;		
int main()
{int i = 0;// void 返回值, int 参数类型function<void(int)> f;   // 函数指针f = func;useF(f, i);// 仿函数f = Functor();useF(f, i);// lambda 表达式f = [](int i) { i++; };useF(f, i);return 0;
}

在这里插入图片描述
function 包装器也可以包装静态成员函数, 只需指明类型.

class Func
{
public:static void func(){}
};int main()
{int i = 0;// void 返回值, 无参数类型function<void()> f;f = Func::func;return 0;
}

若绑定非静态成员函数, 非静态成员函数中有隐藏的 this 指针, 需要将类的对象一起传入.

class Add
{
public:int add(int i, int j){return i + j;}
};int main()
{int i = 0;// int 返回值, Add, int, int 参数类型function<int(Add, int, int)> f;Add a;f = &Add::add;cout << f(Add(), 1, 1) << endl;return 0;
}

在这里插入图片描述
也可以传对象的指针, 但必须是左值的对象, 右值是没有地址的.

class Add
{
public:int add(int i, int j){return i + j;}
};int main()
{int i = 0;// int 返回值, Add*, int, int 参数类型function<int(Add*, int, int)> f;Add a;f = &Add::add;cout << f(&a, 1, 1) << endl;return 0;
}

三. bind 绑定

bind 是一个函数模板, 包含在 <functional> 头文件中, bind 可以接受一个可调用对象(callable object), 然后生成一个新的可调用对象来 “适应” 原对象的参数列表.

bind 可以调整可调用对象的参数 – 包括调整参数顺序和调整参数个数.

template <class Fn, class... Args>
bind (Fn&& fn, Args&&... args);
  • 参数:
    fn: 需要绑定的函数或函数对象的指针;
    args: 可变参数包, 是函数或函数对象需要调整的参数, 也可以使用占位符(placeholders)对参数进行占位, 表示该位置的参数需要在调用时再传递进来.

placeholders 是 C++11 引入的一个命名空间, 其中的 _1, _2, …, _N 称为占位符,分别表示函数中的第 1, 2, …, N 位参数, 可以直接使用
例: 调整参数顺序

int func(int i, int j)
{return i - j;
}int main()
{int i = 0;//                  _2 代表实参的第二个参数, _1 代表实参的第一个参数auto f = bind(func, placeholders::_2, placeholders::_1);// 1 传参给 _1, _1 传参给 j;  2 传参给 _2, _2 传参给 i;cout << f(1, 2) << endl;return 0;
}

可以和包装器配合使用, 调整参数的个数

class Add
{
public:int add(int i, int j){return i + j;}
};int main()
{Add a;int i = 0;// int 返回值, Add, int, int 参数类型function<int(int, int)> f;f = bind(&Add::add, Add(), placeholders::_1, placeholders::_2);cout << f(1, 1) << endl;return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/788445.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【FTP,EMail】

文章目录 FTPFTP&#xff1a;文件传输协议FTP: 控制连接与数据连接分开FTP命令、响应 EMail电子邮件&#xff08;EMail&#xff09;邮件服务器EMail: SMTP [RFC 2821]SMTP&#xff1a;总结 FTP FTP&#xff1a;文件传输协议 向远程主机上传输文件或从远程主机接收文件。客户/服…

使用tcpdump和wireshark进行服务器抓包分析

目录 前言 1.tcpdump简介 2.Wireshark简介 3.实际案例 4.代码示例 5.总结 前言 服务器抓包分析是一种非常常见和有效的网络故障排查和性能优化手段。通过捕获服务器上的网络流量&#xff0c;可以帮助我们深入了解服务器与其它设备之间的通信情况&#xff0c;发现问题并进…

Java多线程实战-从零手搓一个简易线程池(三)线程工厂,核心线程与非核心线程逻辑实现

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️本系列源码仓库&#xff1a;多线程并发编程学习的多个代码片段(github) &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正…

Mac上怎么合并多张图片?

Mac上怎么合并多张图片&#xff1f;上班过的小伙伴都应该知道&#xff0c;合并拼接图片是一件非常重要且经常需要使用到的图片处理技术&#xff0c;将多张图片合并拼成一张之后能够展现出更多的图片内容。在Mac电脑上&#xff0c;合并多张图片是一项常见的任务&#xff0c;无论…

【教程】Kotlin语言学习笔记(六)——泛型

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【Kotlin语言学习】系列文章 第一章 《认识Kotlin》 第二章 《数据类型》 第三章 《数据容器》 第四章 《方法》 第五章 《L…

关系型数据库设计

目录 1.数据库设计的重要性及定义 1.1 数据库设计的重要性 1.1.1 失败的数据库设计造成的后果 1.1.2 优秀的数据库设计带来的好处 1.2 数据库设计的定义 2.数据库需求分析 2.1 需求分析的步骤 2.1.1 收集信息 2.1.2 标识实体 2.1.3 标识每个实体的详细信息 2.1…

【HTML】制作一个简单的动态SVG图形

目录 前言 开始 HTML部分 CSS部分 效果图 总结 前言 无需多言&#xff0c;本文将详细介绍一段HTML和CSS代码&#xff0c;该代码用于创建一个动态的SVG图形&#xff0c;具体内容如下&#xff1a; 开始 首先新建文件夹&#xff0c;创建两个文本文档&#xff0c;其中HTML的文…

【2023】kafka原生以及配合springboot的使用(Kafka-3)

&#x1f4bb;目录 前言 一、依赖二、原生使用kafka1、发送消息1.1、生产者同步发送消息1.2、生产者异步发送消息1.3、常用配置&#xff1a; 2、接收消息2.1、关于消费者的自动提交和手动提交2.2、长轮训poll消息2.3、消费者的健康状态检查2.4、指定分区和偏移量&#xff0c;时…

使用docker-tc对host容器进行限流

docker-tc是一个github开源项目&#xff0c;项目地址是https://github.com/lukaszlach/docker-tc。 运行docker-tc docker run -d \ --name docker-tc \ --network host \ --cap-add NET_ADMIN \ --restart always \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /var…

Transformer - model architecture

Transformer - model architecture flyfish Transformer总体架构可分为四个部分: 输⼊部分 输出部分 编码器部分 解码器部分 输入部分 输出部分 输⼊部分包含: 源嵌⼊层和位置编码 ⽬标嵌⼊层和位置编码 输出部分包含: 线性层 softmax处理器 左侧编码器部分和右侧解码器部…

微信小程序自定义弹窗组件

业务背景&#xff1a;弹窗有时字体较多&#xff0c;超过7个字&#xff0c;不适用wx.showToast. 组件代码 <view class"toast-box {{isShow? show:}}" animation"{{animationData}}"><view class"toast-content" ><view class&q…

Taro + vue3 小程序封装标题组件

分为没有跳转页面的title组件和 有跳转页面的title组件 我们可以把这个封装成一个组件 直接上代码 <template><div class"fixed-title-container"><div class"box"><div class"icon" v-if"isShow" click"…

【论文阅读】DETR 论文逐段精读

【论文阅读】DETR 论文逐段精读 文章目录 【论文阅读】DETR 论文逐段精读&#x1f4d6;DETR 论文精读【论文精读】&#x1f310;前言&#x1f4cb;摘要&#x1f4da;引言&#x1f9ec;相关工作&#x1f50d;方法&#x1f4a1;目标函数&#x1f4dc;模型结构⚙️代码 &#x1f4…

ubuntu-server部署hive-part4-部署hive

参照 https://blog.csdn.net/qq_41946216/article/details/134345137 操作系统版本&#xff1a;ubuntu-server-22.04.3 虚拟机&#xff1a;virtualbox7.0 部署hive 下载上传 下载地址 http://archive.apache.org/dist/hive/ apache-hive-3.1.3-bin.tar.gz 以root用户上传至…

多层PCB内部长啥样?

硬件工程师刚接触多层PCB的时候&#xff0c;很容易看晕。动辄十层八层的&#xff0c;线路像蜘蛛网一样。 画了几张多层PCB电路板内部结构图&#xff0c;用立体图形展示各种叠层结构的PCB图内部架构。 高密度互联板(HDI)的核心 在过孔 多层PCB的线路加工&#xff0c;和单层双…

Transformer - Positional Encoding 位置编码 代码实现

Transformer - Positional Encoding 位置编码 代码实现 flyfish import torch import torch.nn as nn import torch.nn.functional as F import os import mathclass PositionalEncoding(nn.Module):def __init__(self, d_model, dropout, max_len5000):super(PositionalEnco…

深度学习理论基础(六)注意力机制

目录 深度学习中的注意力机制&#xff08;Attention Mechanism&#xff09;是一种模仿人类视觉和认知系统的方法&#xff0c;它允许神经网络在处理输入数据时集中注意力于相关的部分。通过引入注意力机制&#xff0c;神经网络能够自动地学习并选择性地关注输入中的重要信息&…

http: server gave HTTP response to HTTPS client 分析一下这个问题如何解决中文告诉我详细的解决方案

这个错误信息表明 Docker 客户端在尝试通过 HTTPS 协议连接到 Docker 仓库时&#xff0c;但是服务器却返回了一个 HTTP 响应。这通常意味着 Docker 仓库没有正确配置为使用 HTTPS&#xff0c;或者客户端没有正确配置以信任仓库的 SSL 证书。以下是几种可能的解决方案&#xff1…

半导体制程离子注入注入的是哪些离子

离子注入是一种低温过程 通过该过程将一种元素的离子加速进入固体靶材&#xff0c;从而改变靶材的物理、化学或电学性质。离子注入用于半导体器件制造和金属精加工以及材料科学研究。如果离子停止并保留在目标中&#xff0c;则它们可以改变目标的元素成分&#xff08;如果离子…

6 个典型的Java 设计模式应用场景题

单例模式(Singleton) 场景: 在一个Web服务中,数据库连接池应当在整个应用生命周期中只创建一次,以减少资源消耗和提升性能。使用单例模式确保数据库连接池的唯一实例。 代码实现: import java.sql.Connection; import java.sql.SQLException;public class DatabaseConne…