【C++】C++11新特性 function

news2024/11/13 9:32:59

包装器function

  • 一、包装器的引入
  • 二、包装器的介绍
  • 三、bind函数的介绍

一、包装器的引入

在C++中我们的可调用对象是很多的,例如函数指针,仿函数,lambda表达式,这多的可调用对象极大的丰富了C++的功能,但是也给我们带来了一些麻烦,例如在模板中,我们需要一个参数确定的可调用对象作为类型时,如果我们选择传递函数指针,就会得到一份关于函数指针的模板函数,传递的是一个仿函数,就会得到一份关于仿函数的模板函数,传递的是lambda表达式,就会得到一份关于lambda的模板函数。但是这些可调用对象是非常相似的,我们的模板却生成了3份函数,导致模板的效率低下!为了解决这个问题C++11引入了包装器,如果可调用对象的签名式相同那么它们就可以呈现出一个统一的类型

下面是不使用包装器的模板

template<class F, class T>
T useF(F f, T x)
{
	return f(x);
}

double f(double i)
{
	return i / 2;
}

struct Functor
{
	double operator()(double d)
	{
		return d / 3;
	}
};

int main()
{
	// 函数名  ---> 实例化一份函数指针类型
	cout << useF(f, 11.11) << endl;
	// 函数对象   ---> 实例化一份函数对象类型
	cout << useF(Functor(), 11.11) << endl;
	// lamber表达式 ---> 实例化一份函数对象类型
	cout << useF([](double d)->double { return d / 4; }, 11.11) << endl;
	return 0;
}

二、包装器的介绍

std::function在头文件

// 类模板原型如下
template <class T> function; // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;

模板参数说明:
Ret: 被调用函数的返回类型
Args…:被调用函数的形参

如果我们要包装一个函数只要这样书写,包装后定义出的对象使用的还是包装前的可调用对象。

function<返回值(参数,参数,参数...)>

上面的代码经过包装器包装,模板只会生成一份函数

#include <functional>
template<class F, class T>
T useF(F f, T x)
{
	static int count = 0;
	cout << "count:" << ++count << endl;
	cout << "count:" << &count << endl;
	return f(x);
}

double f(double i)
{
	return i / 2;
}

struct Functor
{
	double operator()(double d)
	{
		return d / 3;
	}
};

int main()
{
	// 对函数名进行包装
	std::function<double(double)> func1 = f;
	cout << useF(func1, 11.11) << endl;
	// 对函数对象进行包装
	std::function<double(double)> func2 = Functor();
	cout << useF(func2, 11.11) << endl;
	// 对lamber表达式进行包装
	std::function<double(double)> func3 = [](double d)->double { return d / 4; };
	cout << useF(func3, 11.11) << endl;
	
	return 0;
}

可以看出通过function对C++中各种可调用实体(普通函数、Lambda表达式、仿函数)的封装,形成一个新的可调用的function对象,让我们不再纠结那么多可调用的实体,有种“万众归一”,一切变得简单的感觉。

此外包装器也可以包装成员函数,但是如果包装非静态的成员函数:

  • 被包装的成员函数前面要加&,而且第一个参数要传递类的类型,
  • 在调用时第一个参数要传递一个类对象,由这个类对象去调用成员函数。
 //function 对成员函数进行包装
class Plus
{
public:
	Plus(int factor = 2)
		:_factor(factor)
	{}
	static int plusi(int a, int b)
	{
		return a + b;
	}
	double plusd(double a, double b)
	{
		return (a + b) * 2;
	}
private:
	int _factor;
};

int main()
{
	function<int(int, int)> f1 = Plus::plusi;
	// 非静态成员函数前面要加&
	function<double(Plus*, double, double)> f2 = &Plus::plusd;

	cout << f1(1, 2) << endl;
	cout << f2(Plus(), 1, 2) << endl;
}

三、bind函数的介绍


bind函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。一般而言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M可以大于N,但这么做没什么意义)参数的新函数。同时,使用bind函数还可以实现参数顺序调整等操作。

在这里插入图片描述

调用bind的一般形式:auto newCallable = bind(callable,arg_list);
  • newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。当我们调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数。

  • arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是占位符,表示newCallable的参数,它们占据了传递给callable的参数的“位置”。数值n表示生成的可调用对象中参数的位置:_1为callable的第一个参数,_2为第二个参数,以此类推。

  • 这些占位符在一个叫placeholders的一个命名空间内!

功能1:改变参数的顺序

int sub(int x, int y)
{
	return x - y;
}

int main()
{
	cout << sub(10, 5) << endl;
	// 调整参数的位置
	auto newsub = bind(sub, placeholders::_2, placeholders::_1);
	// 或者这样写也许
	//function<int(int,int)> func = bind(sub, placeholders::_2, placeholders::_1);
	cout << newsub(10, 5) << endl;
}

在这里插入图片描述

在这里插入图片描述

功能2:改变参数的个数

类内成员要传递三个参数,我们直接让第一个参数固定绑死!这样我们的新函数就可以只传递两个参数了

class Plus
{
public:
	Plus(int factor = 2)
		:_factor(factor)
	{}
	static int plusi(int a, int b)
	{
		return a + b;
	}
	double plusd(double a, double b)
	{
		return (a + b) * 2;
	}
private:
	int _factor;
};

int main()
{
	auto newplusd = bind(&Plus::plusd, Plus(3), placeholders::_1, placeholders::_2);
	cout << newplusd(1, 2) << endl;
}

在这里插入图片描述

在这里插入图片描述

又例如我们进行这样的特殊绑定,绑定第2个参数

class Plus
{
public:
	Plus(int factor = 2)
		:_factor(factor)
	{}
	static int plusi(int a, int b)
	{
		return a + b;
	}
	double plusd(double a, double b)
	{
		return (a + b) * 2;
	}
private:
	int _factor;
};

int main()
{
	auto newplusd = bind(&Plus::plusd, placeholders::_1, 1, placeholders::_2);
	cout << newplusd(Plus(3), 2) << endl;
}

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

Python continue 语句

Python continue 语句跳出本次循环&#xff0c;而break跳出整个循环。 continue 语句用来告诉Python跳过当前循环的剩余语句&#xff0c;然后继续进行下一轮循环。 continue语句用在while和for循环中。 Python 语言 continue 语句语法格式如下&#xff1a; continue 流程图…

PaddleOCR训练部署文档

Cuda安装 wget https://developer.download.nvidia.com/compute/cuda/11.6.0/local_installers/cuda_11.6.0_510.39.01_linux.run sh cuda_11.6.0_510.39.01_linux.run#可能会报错&#xff0c;查看/var/log/nvidia-installer.log &#xff0c;kill -9 [ID]可以解决vim ~/.bash…

计算机网络 第一章:概述

目录 一.因特网概述 1.1网络、互联网(互连网)和因特网 1.2internet与Internet的区别 1.3因特网服务提供者ISP(Internet Service Provider) 1.4因特网组成 二.三种交换方式 2.1电路交换 2.2分组交换(重点) 2.3报文交换 三.计算机网络的定义和分类 四.计算机网络的性能…

前端居中截取不同形状的图片

开发的时候拿到这样一个需求: 意思就是要居中截取图片,这个功能跟微信朋友圈的九宫格显示功能差不多的效果。 方案一 用样式居中,这种方案适合紧急情况下的临时方案 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8&…

华为云云耀云服务器L实例评测|基于华为云云耀云服务器L实例搭建MySQL集群并开展性能评测

文章目录 华为云云耀云服务器L实例的使用搭建MySQL集群环境搭建安装MySQL数据库 集群搭建安装Galera Cluster配置MySQL启动集群 性能测试安装sysbench创建测试数据库运行性能测试 使用Superset从MySQL数据源中获取数据进行分析准备工作配置MySQL数据源从MySQL数据源中获取数据 …

基于Java+SpringBoot+Vue前后端分离的房屋租赁管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 房屋租赁管理系统是一…

029:vue项目,勾选后今天不再弹窗提示

第029个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

【校招VIP】前端算法考察之字符串

考点介绍 说到字符串算法我们最先想到的就是模式匹配问题&#xff0c;所谓模式匹配就是字符串匹配问题&#xff0c;就是在一个长的主串中寻找子串的过程&#xff0c;如果我们直接暴力匹配那就是最基本的BF算法&#xff1b;KMP算法与BF算法最大的区别区别就是主串不进行回溯。 …

PaddleOCR学习笔记1-初步尝试

尝试使用PaddleOCR方法&#xff0c;如何使用自定义的模型方法&#xff0c;参数怎么配置&#xff0c;图片识别尝试简单提高识别率方法。 目前仅仅只是初步学习下如何使用PaddleOCR的方法。 一&#xff0c;测试识别图片&#xff1a; 1.png : 正确文本内容为“哲学可以帮助辩别现…

向左偏移的云应用容器监控方法

向左偏移是一种在软件开发生命周期的早期强调测试、监控和自动化的软件开发和操作方法。向左偏移方法的目标是通过尽早发现问题并迅速解决&#xff0c;从而预防问题的发生。 当您尽早发现可扩展性问题或错误时&#xff0c;解决它将更加迅速和经济高效。将低效的代码移动到云容…

使用Jsmooth打包JavaFx程序为EXE文件

配置IDEA 第一步&#xff1a; 第二步&#xff1a; MANIFEST.MF的文件路径&#xff0c;必须在resources文件夹中&#xff0c;如果没有&#xff0c;就创建一个。 第三步&#xff1a;配置项目所需jar包的相对路径 最后&#xff1a; 点击确定后&#xff0c;编译Jar 配置Jsmooth …

Docker从认识到实践再到底层原理(四-1)|Docker镜像仓库|超详细详解

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…

k8s node环境部署(三)

1、添加node1、node2环境 前面配置master环境的截图最后一段 复制下来 分别在node主机执行 kubeadm join 192.168.37.132:6443 --token p5omh3.cqjqt8ymrwkdn2fc \ --discovery-token-ca-cert-hash sha256:608a1cbadd060cfdeac2fae84c19609061b750ab51bf9a19887ff7ea…

恒运资本:消费电子概念再爆发,冠石科技三连板,捷荣技术9日大涨127%

消费电子概念8日盘中再度走高&#xff0c;截至发稿&#xff0c;利和兴涨近15%&#xff0c;日久光电、冠石科技、捷荣技能、华映科技、东睦股份等涨停&#xff0c;大富科技涨超7%。 值得注意的是&#xff0c;冠石科技已接连3日涨停&#xff0c;公司昨日晚间发布危险提示称&…

数字钥匙关键技术:UWB(超宽带)实现原理一文讲透

在之前的文章《一文讲透超宽带&#xff08;UWB&#xff09;前世今生》中&#xff0c;我们从起源、定义、标准、发展、应用等角度概述了UWB技术。根据UWB的特性&#xff0c;其基础功能分为&#xff1a;数据传输、雷达成像、测距定位。接下来我们将概述其数据传输和雷达成像功能&…

YOLOV7改进-对小目标有效的BiFormer注意力机制

如果要在sppcspc后面加一个注意力模块BiFormer 1、 普通加 1、models-common.py搜这个模块 2、直接加 3、全部复制下来&#xff0c;models新建文件 4、common导入进来 5、填上一层的输出通道数 2、模块里加 难点&#xff1a;在配置文件找到对应的这一块 yolov7x中 1、…

GE IS220PDIAH1A 336A4940CSP1 控制主板模块

GE IS220PDIAH1A 336A4940CSP1 是一款控制主板模块&#xff0c;通常用于工业自动化和控制系统中。以下是可能与这种控制主板模块相关的一些产品功能&#xff1a; 信号处理&#xff1a; GE IS220PDIAH1A 336A4940CSP1控制主板模块通常负责信号处理&#xff0c;可以接收、放大、滤…

机器学习算法基础--线性回归算法

目录 1.算法求解步骤 2.算法核心代码 3.算法效果展示 1.算法求解步骤 线性回归算法流程: #1.数据导入与处理 #2.创建线性回归模型并拟合数据 #3.计算回归直线的斜率和截距 #4.预测 x5 时的y值 #5.进行进一步预测 #5.进行进一步预测 2.算法核心代码 #机器学习算法基础第一…

数据结构与算法:练习与实践的重要性

文章目录 为什么练习与实践很重要&#xff1f;1. 熟练应用2. 问题解决能力3. 代码效率4. 面试准备 如何练习与实践&#xff1f;1. 在线评测平台2. 自主设计数据结构3. 解决不同类型的问题 持续学习与实践 &#x1f389;欢迎来到数据结构学习专栏~数据结构与算法&#xff1a;练习…

MySQL使用CASE WHEN统计SQL语句代替子查询SQL统计,CASE WHEN常用写法,根据不同的条件对数据进行分类、分组和聚合

MySQL中&#xff0c;写一个CASE WHEN的统计SQL语句&#xff0c;代替子查询SQL统计语句 假设我们有一个名为"orders"的表&#xff0c;其中包含订单信息&#xff0c;包括订单号(order_id)、订单金额(order_amount)等列。我们想要统计每个订单级别的订单数量&#xff0c…