C++11bind、function、lambda详细讲解

news2024/11/26 20:29:01

一.lambda表达式

        关于lambda表达式,我之前是详细讲过的,现在我们只来做重点讲解(如果存在疑问可以回看我之前的作品)。

固定格式:

        []()->返回值{};([capture-list] (parameters) mutable -> return-type { statement}
capture-list:可以自写[],表示不传递任何变量到该作用域,当然也可以如下:

[capture-list]:不能省流(最基础为[])
----------------------------------------------------------------
[var]:表示值传递方式捕捉变量var
[=]:表示值传递方式捕获所有父作用域中的变量(包括this)
[&var]:表示引用传递捕捉变量var
[&]:表示引用传递捕捉所有父作用域中的变量(包括this)
[this]:表示值传递方式捕捉当前的this指针
-----------------------------------------------------------------
例子如下:
//1.[]不传递任何变量
//2.[=]表示以传值的方式传递作用域外面的所有变量
//3.[&}表示以传引用的方式传递作用域外面的所有变量
//4.[=,&a]表示a变量以传引用传递,其余变量都以传值传递
//5.[&,b]表示a变量以传值传递,其余都以传引用传递
//6.[a,&b]表示a以传值传递,b以传引用传递
//7.[this]传递父作用域中的this指针

(parameters):表示参数,如果不传参可以省略(模仿函数参数写即可)

mutable 这个不常用,相信大家了解不多,其是一个关键字,表示可变的,与const恰好相反,mutable是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。例子如下:

class Test
{
public:
    Test(int count=0):_count(count){};
    //析构默认
    vois print() const
    {
        _count++;
        std::cout<<"hello world! this is "<< _count<< " times" << std::endl;
    }
private:
    mutable int _count;//记录输出次数
};

//对于该类对象,print函数是被const修饰的,但是我们想要改变_count的值,所以这种情况下就可以使用_mutable 关键字来使被修饰的变量可以改变

-> return-type:->后面加上返回值类型,如果是void,可以直接全部省略

{ statement}:类似函数体,如果不需要写内容,可以直接写{}

总结:

最简单的lambda表达式:
[]{];//当然没有任何实际意义,大家可以用其理解那些部分不可省略

例子:
int main()
{
    int a=10,b=20;
    auto func1=[=](int c)->int{return a+b-c;};//注意两个“;”,不要忘了函数体中的分号
    std::cout<<func1(15)<<std::endl;
    return 0;
}

补充知识:lambda表达式之间不能赋值,即使看起来类型相似(底层学习):

lambda表达式在底层中会被当成函数对象处理(仿函数),以VS为例,在vs底层会将灭一个lambda表达式
生成一个固定的uuid,每一个都不同,uuid就可以看做类名,而lambda表达式的类型在VS中会被认为是
lambda+uuid,因为uuid不同,每一个lambda表达式的类型都是唯一,因此不能相互赋值,即使如下:
auto f1 = []{cout << "hello world" << endl; };
auto f2 = []{cout << "hello world" << endl; };
这两个看起来类型相同的lambda表达式
实际上类型都是唯一的


二.function包装器

function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器
我们还是先知道如何使用再来讲为什么需要它?

//首先:头文件为:
#include <functional>
模版:
function<返回值(参数)> 包装器名(函数名等);
function<返回值(参数)> 包装器名=函数名等;
//主要使用情况如下4种:

//1.函数名(函数指针)形式
int sum(int x,int y){return x+y;};
void Test1()
{
    std::function<int(int,int)> func1=sum;
    std::cout<<func1(1,2)<<std::endl;;//通过func1调用sum函数
    //注意点:区分函数指针如何写:返回值类型(*函数指针名)(参数);
}
//2.函数对象(仿函数)
class Functor
{
public:
    int operator()(int a,int b)
    {
        return a+b;    
    }
};
void Test2()
{
    std::function<int(int,int)> func2(&Functor);
    //等价于:std::function<int(int,int)> func2=Functor();
    std::cout<<func2(2,3)<<std::endl;
}
//3.lambda表达式
void Test3()
{
    std::function<void(const string)> func3=[](const string str){
    std::cout<<str<<std::endl;};
    func3("hello world");
}
//4.类成员函数
class Count
{
    public:
        double del(double x,double y)
        {
            return x/y;
        }
}
void Test4()
{
    std::function<double(double,double)> func4=&Count::del;
    std::cout<<func4(3.2,2.0)<<std::endl;
}

当然,对于例四也可以将类名传递,但是要注意类要取地址!!!

        下面我们再来讲下为什么要在C++11中加入function包装器呢?

        目的是为了解决模版效率低下问题,模版为什么说效率低下,看下面这个语句:

ans=Func1(x);对于该语句Func1可能是函数指针,也可能是仿函数对象,更可能是lambda对象、函数名等等,如此多的类型,模版推演的效率自然就低下了,因此在C++11中引入了包装器function,这样我们通过function包装可以清晰的调用该调用的函数、lambda等,自然效率就高了。

包装器在实际运用时作用非常广泛,大家可以自行了解。

补充知识:

在该部分开始时,我们放出了包含如下语句

template <class Ret, class... Args>
class function<Ret(Args...)>;

的照片,现在补充解释下"..."的作用:

1.在class中"...”位于模版名前面,表示可变参数列表

2.在运用Args时在其后加“...”表示对参数的可变化



三.bind1st/bind2nd/bind

        上面三个都是绑定器,第一个和第二个是STL中提供的,bind则是C++11引入boost中的内容提出的,下面我们下来学习前两个:

bind1st简单来说就是将第一个参数绑定,这样就可以解决需要两个参数,但是函数形参只有一个的问题,具体例子:

#include <iostream>
#include <functional>
#include <algorithm>
#include <vector>
int main()
{
	std::vector<int> arr = { 1,25,7,21,66,10 };
	sort(arr.begin(), arr.end(), std::greater<int>());//从大到小排序
	for (auto a : arr)
	{
		std::cout << a << " ";
	}
	std::cout << std::endl;
	//现在想在插入27
	auto iter = find_if(arr.begin(), arr.end(), std::bind1st(std::greater<int>(),27));
	std::cout << *iter << std::endl;//找到从大到小的25
	//插入27
	arr.insert(iter, 27);
	for (auto a : arr)
	{
		std::cout << a << " ";
	}
	std::cout << std::endl;
	return 0;
}

在该例子中我们需要注意:

1.bind1st第一个参数通常是函数对象,第二个参数则是T val,通过绑定我们就可以讲greater仿函数所需要的两个参数变成一个,第一个参数是bind1st绑定的值,第二个为arr中值,从而变成找第一个小于27的位置迭代器

2.find_if函数的理解:前两个参数传迭代器,第三个参数可以是仿函数,也可以是bind,这也揭示了其本质上也是一个函数模版

该大体与bind1st相似,主要区别在于greater中第二个参数才是bind绑定的值,第一个是arr中的值,在绑定时写法和上面一样

​
bind1st(greater<int>(),27);
bind2nd(greater<int>(),27);
//这里位置一样的,别记错了!!!

​

大家应该会发现,我们绑定器无论是bind1st,还是bind2nd,都只能处理二元函数(两个参数),对于多元函数是没法处理的,这也是bind提出的原因,下面我们就来进入本文的最后一个话题:bind绑定器

大家一看这张图片就会明白我们之前的补充,可变参数,即bind的参数可变的,对于bind我们可以直接来学习内容,就没必要讲解其他部分(原因等):

        首先,bind有一个placeholders,有1-20左右,可以先通过bind绑定placeholders_1等,然后传递实际参数,例子如下:

//注意:头文件件还是<functional>
#include <functional>
//1.bind绑定函数:
int sum(int a,int b)
{
    return a+b;
}
void Test1()
{
    std::function<int(int,int)> func1=std::bind(sum,std::placeholders::_1,std::placeholders::_2);
    std::cout<<func1(1,2)<<std::endl;//输出:3
}
//2.bind绑定类成员函数:
class Functor
{
public:
	int sub(int x, int y)
	{
		return x - y;
	}
};
void Test2()
{
    std::function<int(int, int)> func2 = std::bind(&Functor::sub,             
    Functor(),std::placeholders::_1, std::placeholders::_2);
    std::cout << func2(1, 2) << std::endl;//结果是:-1
    std::function<int(int, int)> func3 = std::bind(&Functor::sub, Functor(), 
    std::placeholders::_2, std::placeholders::_1);
    std::cout << func3(1, 2) << std::endl;//交换_1和_2的顺序,结果是:1
}
//绑定类成员函数时,第一个参数为&类名::函数,第二个参数为类对象,后面为可变参数

最后,祝大家国庆快乐!!!

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

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

相关文章

UE行为树编辑器图文笔记

对UE的编辑器实现有点好奇&#xff0c;于是从比较熟悉的行为树编辑器着手分析。以下为阅读UE源码后的个人理解&#xff0c;如有错误请指正。 编辑器基础 扩展编辑器的几种方式 MenuBar 菜单栏ToolBar 工具栏DetailCustomization 自定义细节面板&#xff0c;支持两种方式&…

西安做网站如何打造出色的企业网站

西安做网站如何打造出色的企业网站 随着数字化时代的到来&#xff0c;企业网站已成为展示企业形象、传播品牌价值的重要平台。在西安&#xff0c;如何打造出色的企业网站呢&#xff1f;以下几点建议可以帮助企业在激烈的竞争中脱颖而出。 **1. 清晰的网站定位** 首先&#xff…

【Godot4.3】匀速和匀变速直线运动粒子

概述 本篇论述&#xff0c;如何用加速度在Godot中控制粒子运动。 匀速和匀变速直线运动的统一 以下是匀变速运动的速度和位移公式&#xff1a; v t v 0 a t x t v 0 t 1 2 a t 2 v_tv_0 at \\ x_tv_0t \frac{1}{2}at^2 vt​v0​atxt​v0​t21​at2 当a 0 时&#xf…

计算机科学英语词汇汇总(下)Computer Science English Complete Vocabulary )

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…

0基础学习QT——配置开发环境

大纲 安装Qt配置Visual Studio 2022安装插件配置 测试 Qt框架&#xff0c;以其跨平台、高性能以及丰富的UI组件库而著称&#xff0c;是开发图形用户界面应用程序的理想选择。Visual Studio 2022提供了对Qt项目的深度支持&#xff0c;包括智能代码提示、代码导航、调试工具等&am…

(14)MATLAB莱斯(Rician)衰落信道仿真4

文章目录 前言一、改写莱斯分布概率密度函数的理论值二、仿真代码三、仿真结果总结 前言 本文通过将接收信号总功率设置为1&#xff0c;重写了莱斯衰落信道上接收信号幅度的理论PDF式。然后用MATLAB代码生成了在具有不同莱斯因子K的Ricean平坦衰落信道下接收到的信号样本&…

容器适配器-stack、queue、priority_queue和仿函数

目录 1.什么是适配器 2.deque 1.简单了解结构 2.deque的缺陷 3.为什么选择deque作为stack和queue的底层默认容器 3.stack&#xff08;栈&#xff09; 4.queue&#xff08;队列&#xff09; 5.仿函数 6.priority_queue&#xff08;优先级队列&#xff09;&#xff08;堆…

PlantUML中的实体关系图

概述 实体关系图&#xff08;Entity Relationship Diagrams&#xff0c;ERD&#xff09;是一种被广泛用于数据库建模的图。 1976年美籍华裔计算机科学家陈品山&#xff08;Peter Chen&#xff09;首次提出了Entity Relationship Modeling&#xff08;实体关系建模&#xff09…

数据结构-单链表的反转

一直在路上 目录 前言一、普通方法二、头插法三、递归法总结 前言 本篇文章介绍反转单链表的三种方法&#xff0c;分别为普通方法、头插法、递归法。 一、普通方法 普通方法是从第一个结点开始反转&#xff0c;然后反转剩余的结点。 普通方法需要保存当前结点的前驱和后继&a…

DevExpress WinForms v24.1新版亮点:富文本编辑器、电子表格组件功能升级

DevExpress WinForms拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜…

自动驾驶-轨迹拼接

在进行自动驾驶的规划之前&#xff0c;要确定当前帧轨迹规划的起点&#xff0c;这个起点常被误认为是当前车辆的位置&#xff0c;即每次以车辆的当前位置进行轨迹规划&#xff1b;其实不是这样的&#xff0c;直观上&#xff0c;这会导致本次次规划的轨迹同上次规划的轨迹之间是…

如何计算服务需要部署多少台机器?

写在前面 遇到流量激增的性能问题&#xff0c;相信绝大多数人的第一反应不是优化代码而是加机器&#xff01;比如隔壁微博一旦出现爆炸性吃瓜&#xff0c;就会紧急扩机器&#xff0c;防止自己服务被打挂&#xff08;虽然经常被打挂 这篇文章我们就来讲一下如何 计算出一个服务…

项目配置说明

文章目录 一、下载 vscode 并安装相应扩展1.1 下载 vscode1.2 安装扩展 二、git 项目三、git 提交流程3.1 确定要提交的代码 四、git 拉新流程 一、下载 vscode 并安装相应扩展 1.1 下载 vscode vscode 我已经发群里了&#xff0c;或者自己去官网下载也行 1.2 安装扩展 打开…

四舵轮车辆中的舵轮角度计算

对于四舵轮车辆&#xff0c;或者对角线安装的双舵轮车辆来说&#xff0c;当同时存在线速度与角速度的时候&#xff0c;它的两个轮子的角度值是不一样的&#xff0c;而它的角度值与其当时的瞬心相关&#xff08;机器人模型与ICR(Instantaneous Center of Rotation)&#xff09;。…

IP6537_C_30W20V--移动设备快充的得力助手,集成 14 种快充协议的降压 SoC

IP6537_C_30W20V是一款集成同步开关的降压转换器、支 持 14 种输出快充协议、支持 Type-C 输出和 USB PD2.0/PD3.0(PPS)协议的 SoC&#xff0c;为车载充电器、 快充适配器、智能排插提供完整的解决方案。 IP6537_C_30W20V支持 USB Type-C 或者 USB A 输出&#xff0c; 5V 输出功…

火语言RPA流程组件介绍--模拟键盘输入

&#x1f6a9;【组件功能】&#xff1a;在浏览器网页中使用键盘操作模拟输入值 配置预览 配置说明 按键间隔(ms) 支持T或# 输入仅支持整型 两次输入按键的间隔,单位毫秒 输入内容 支持T或# 默认FLOW输入项 需要输入的内容 超时时间 支持T或# 输入仅支持整型 输入的超时时…

我们的赞赏码

每一位粉丝的认可&#xff0c;都是我们前进的动力。欢迎为我们点赞、转发和分享&#xff0c;让我们一起传递美好与快乐&#xff01; 我们真诚地邀请您来赞赏我们&#xff0c;您的认可是我们前进的动力&#xff01; 赞赏我们只要0.99&#xff0c;让我们一起在CSDN增长知识&…

OpenAI 开发者大会!实时语音功能有API了,GPT-4o支持多模态微调,上下文cache功能上线

家人们&#xff01;十一假期第1天&#xff0c; OpenAI一年一度的开发者大会又来了惹&#xff01;今年的开发者大会分成三部分分别在美国、英国、新加坡三个地点举办&#xff0c;刚刚结束的是第一场。 去年的OpenAI开发者大会公布了GPT-4 Turbo和GPTs&#xff0c;今年没有大更新…

【硬件模块】SG90舵机模块

SG90舵机模块实物图 180度舵机&#xff1a;可以控制旋转角度、有角度定位。上电后舵机自动复位到0度&#xff0c;通过一定参数的脉冲信号控制它的角度。 360舵机&#xff1a;不可控制角度&#xff0c;只能控制顺时针旋转、逆时针旋转、停止和调节转速。 如图所示为&#xff1a;…

仅用pygame+python实现植物大战僵尸-----完成比完美更重要

前言 其实这个项目再我上半年就想着做一下的&#xff0c;但是一直拖到现在&#xff0c;我现在深刻的理解到&#xff0c;不要想那么多&#xff0c;先做&#xff0c;因为永远不可能准备好&#xff0c;都是边做边学便准备的&#xff0c;完成比完美更重要&#xff1b;使用python&a…