33 包装器

c++11
也叫适配器。c++中的function本质是一个类模板,也是一个包装器

为什么需要fuction呢?
当一个类型既可以是函数指针,也可以是仿函数和lambda比倒是,函数指针的类型不好理解,仿函数写起来麻烦,lambda无法拿到类型,有什么办法有统一的函数对象

ret = func(x);
 // 上面func可能是什么呢?那么func可能是函数名?函数指针?函数对象(仿函数对象)?也有可能
是lamber表达式对象?所以这些都是可调用的类型!如此丰富的类型,可能会导致模板的效率低下!
为什么呢?我们继续往下看
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()
 {
 // 函数名
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;
 }

通过上面验证,发现useF函数模板实例化了三份
包装器可以解决上述问题

std::function在头文件<functional>
 // 类模板原型如下
template <class T> function;     
// undefined
 template <class Ret, class... Args>
 class function<Ret(Args...)>;
模板参数说明:
Ret: 被调用函数的返回类型
Args…:被调用函数的形参
void swap_func(int& r1, int& r2)
{
	int tmp = r1;
	r1 = r2;
	r2 = tmp;
}

struct Swap
{
	void operator()(int& r1, int& r2)
	{
		int tmp = r1;
		r1 = r2;
		r2 = tmp;
	}
};

int main()
{
	int x = 0, y = 1;
	cout << x << " " << y << endl;

	auto swaplambda = [](int& r1, int& r2) {
		int tmp = r1;
		r1 = r2;
		r2 = tmp;
	};

	function<void(int&, int&)> f1 = swap_func;
	f1(x, y);
	cout << x << " " << y << endl << endl;

	function<void(int&, int&)> f2 = Swap();
	f2(x, y);
	cout << x << " " << y << endl << endl;

	function<void(int&, int&)> f3 = swaplambda;
	f3(x, y);
	cout << x << " " << y << endl << endl;

	// 11:40继续
	map<string, function<void(int&, int&)>> cmdOP = {
		{"函数指针", swap_func},
		{"仿函数", Swap()},
		{"lambda", swaplambda},
	};

	cmdOP["函数指针"](x, y);
	cout << x << " " << y << endl << endl;

	cmdOP["仿函数"](x, y);
	cout << x << " " << y << endl << endl;

	cmdOP["lambda"](x, y);
	cout << x << " " << y << endl << endl;

	return 0;
}

类函数的包装

类函数需要指定域,成员函数第一个参数是this指针,需要传入

class Plus
{
public:
	static int plusi(int a, int b)
	{
		return a + b;
	}

	double plusd(double a, double b)
	{
		return a + b;
	}
};

int main()
{
	// 成员函数取地址,比较特殊,要加一个类域和&
	function<int(int, int)> f1 = &Plus::plusi;
	cout << f1(1, 2) << endl;

	//成员函数第一个参数默认是this指针
	function<double(Plus*, double, double)> f2 = &Plus::plusd;
	Plus ps;
	cout << f2(&ps, 1.1, 2.2) << endl;
	//和上面类似
	function<double(Plus, double, double)> f3 = &Plus::plusd;
	cout << f3(Plus(), 1.11, 2.22) << endl;

	return 0;
}

类的函数调用每次都要写一个类,有点麻烦,有什么办法省略?

改造题目
https://leetcode.cn/problems/evaluate-reverse-polish-notation/submissions/
在这里插入图片描述

class Solution {
public:
    int evalRPN(vector<string>& tokens) {

        stack<int> st;
        for (auto str:tokens)
        {
            if (str == "+" || str == "-" || str == "*" || str == "/")
            {
                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();

                int ret = 0;
                switch(str[0])
                {
                    case '+':
                        ret = left + right;
                        st.push(ret);
                        break;
                        case '-':
                       ret = left - right;
                        st.push(ret);
                        break;
                        case '*':
                         ret = left * right;
                        st.push(ret);
                        break;
                        case '/':
                        ret = left / right;
                        st.push(ret);
                        break;
                }
            }else
            {
                st.push(stoi(str));
            }
        }

        return st.top();
    }
};

用包装器修改上面:

class Solution {
public:
    int evalRPN(vector<string>& tokens) {

        stack<int> st;
        map<string, function<int(int, int)>> cmdop = 
        {
            {"+", [](int x, int y){return x + y;}},
            {"-", [](int x, int y){return x - y;}},
            {"*", [](int x, int y){return x * y;}},
            {"/", [](int x, int y){return x / y;}}
        };

        for (auto str:tokens)
        {
            if (cmdop.count(str))
            {
                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();

                st.push(cmdop[str](left, right));
            }
            else
            {
                st.push(stoi(str));
            }
        }

        return st.top();
    }
};

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

// 原型如下:
template <class Fn, class... Args>
 /* unspecified */ bind (Fn&& fn, Args&&... args);
 // with return type (2) 
template <class Ret, class Fn, class... Args>
 /* unspecified */ bind (Fn&& fn, Args&&... args);

可以将bind看做一个通用的函数适配器,接受一个可调用对象,生成一个新的可调用对象“适应”原对象的参数列表
调用bind的一般形式:auto newCallable = bind(callable, arg_list);

其中,newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。当我们调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数

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

//绑定第一个参数
function<double(double, double)> f4 = bind(Plus::plusd, Plus(), placeholders::_1, placeholders::_2);
cout << f4(1.11, 2.22) << endl;
int Sub(int a, int b)
{
	return a - b;
}
//参数写死
function<int(int)> f6 = bind(Sub, 20, placeholders::_1);
cout << f6(5) << endl;

int Sub2(int a, int b, int c)
{
	return a - b;
}
//中间写死
function<int(int, int)> f7 = bind(Sub2, placeholders::_1, 20, placeholders::_2);
cout << f7(5, 6) << endl;
return 0;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年工程项目管理者的软件指南:11款必试进度管理工具

本文将分享11个值得关注的工程项目进度管理软件&#xff1a;Worktile、Fieldwire、Procore、Buildxact、InEight、Contractor Foreman、Housecall Pro、ClickUp、RedTeam Go、Visual Planning、B2W Schedule。 在竞争激烈的建筑行业&#xff0c;工程项目的进度管理是项目成功的…

Linux 实现自定义系统调用,支持参数和结果返回

本文实现一个简单的系统调用实现&#xff0c;支持输入字符串参数&#xff0c;并返回一个结果字符串。 以下是验证步骤&#xff1a; 1. 添加系统调用编号 试验使用的是 x86_64 架构的 Linux 内核。 找到并编辑 arch/x86/entry/syscalls/syscall_64.tbl 文件&#xff0c;在文件…

编写动态库

1.创建库.c .h文件 2.编写Makefile文件 3.make之后形成.so文件 4.make output,形成mylib 5.把mylib拷贝到test里面 mv mylib /test 6.编译 gcc main.c -I mylib/include -L mylib/lib -lmymethod形成a.out 但是直接执行会出现以下问题 很显然没有找到动态库 7.解决加载找不…

主干网络篇 | YOLOv8改进之引入YOLOv10的主干网络 | 全网最新改进

前言:Hello大家好,我是小哥谈。YOLOv10是由清华大学研究人员利用Ultralytics Python软件包开发的,它通过改进模型架构并消除非极大值抑制(NMS)提供了一种新颖的实时目标检测方法。这些优化使得模型在保持先进性能的同时,降低了计算需求。与以往的YOLO版本不同,YOLOv10的…

DFS练习

105 从前序与中序遍历序列构造二叉树 import java.util.HashMap; import java.util.Map;class TreeNode {int val;TreeNode left;TreeNode right;public TreeNode(int val) {this.val val;} }public class Letcode105 {public TreeNode bulidTree(int[] preOrder, int[] inOrd…

c++将一个复杂的结构体_保存成二进制文件并读取

在 C 中&#xff0c;可以将复杂的结构体保存到二进制文件中&#xff0c;并从二进制文件中读取它。为了实现这一点&#xff0c;你可以使用文件流库 <fstream>。以下是一个示例&#xff0c;展示如何将一个复杂的结构体保存到二进制文件中&#xff0c;并从二进制文件中读取它…

去中心化经济的革新:探索Web3的新商业模式

随着区块链技术的发展&#xff0c;Web3正逐渐成为全球经济和商业模式的关键词之一。Web3不仅仅是技术的革新&#xff0c;更是对传统中心化商业模式的挑战和重构。本文将深入探讨Web3背后的概念、关键技术以及其带来的新商业模式&#xff0c;带领读者走进这一新兴领域的深度分析…

python如何输出list

直接输出list_a中的元素三种方法&#xff1a; list_a [1,2,3,313,1] 第一种 for i in range(len(list_a)):print(list_a[i]) 1 2 3 313 1 第二种 for i in list_a:print(i) 1 2 3 313 1 第三种&#xff0c;使用enumerate输出list_a方法&#xff1a; for i&#xff0c;j in enum…

中日区块链“大比拼”!中国蚂蚁加大区块链押注资本!日本索尼进军加密货币市场!

科技巨头在区块链和加密货币领域的动作越来越频繁。近期&#xff0c;中国金融科技巨头蚂蚁集团进一步加大了在区块链业务上的投资&#xff0c;而日本电子科技巨头索尼集团则正式进军加密货币交易领域。这些举措反映了两国对于区块链和加密资产领域的不同态度和布局。 蚂蚁集团加…

游戏AI的创造思路-技术基础-关于艾宾浩斯遗忘曲线的迷思

对于艾宾浩斯遗忘曲线和函数&#xff0c;我一直都有小小的迷思&#xff0c;总想实验下用艾宾浩斯函数来替换sigmoid函数作为激活函数&#xff0c;打造更接近人类的AI算法&#xff0c;这篇文章旨在讨论下 目录 3.10. 艾宾浩斯曲线 3.10.1. 定义 3.10.1.1. 曲线计算公式 3.10…

【QT】常用控件|widget|QPushButton|RadioButton|核心属性

目录 ​编辑 概念 信号与槽机制 控件的多样性和定制性 核心属性 enabled geometry ​编辑 windowTiltle windowIcon toolTip styleSheet PushButton RadioButton 概念 QT 控件是构成图形用户界面&#xff08;GUI&#xff09;的基础组件&#xff0c;它们是实现与…

维护Nginx千字经验总结

Hello , 我是恒 。 维护putty和nginx两个项目好久了&#xff0c;用面向底层的思路去接触 在nginx社区的收获不少&#xff0c;在这里谈谈我的感悟 Nginx的夺冠不是偶然 高速:一方面&#xff0c;在正常情况下&#xff0c;单次请求会得到更快的响应&#xff1b;另一方面&#xff0…

深入解析:Java爬虫的本质是什么?

深入解析&#xff1a;Java爬虫的本质是什么&#xff1f; 引言&#xff1a; 随着互联网的快速发展&#xff0c;获取网络数据已成为许多应用场景中的重要需求。而爬虫作为一种自动化程序&#xff0c;能够模拟人类浏览器的行为&#xff0c;从网页中提取所需信息&#xff0c;成为了…

递归算法练习

112. 路径总和 package Tree;import java.util.HashMap; import java.util.Map;class TreeNode {int val;TreeNode left;TreeNode right;public TreeNode(int val) {this.val val;} }/*** 求 树的路径和* <p>* 递归 递减* <p>* 询问是否存在从*当前节点 root 到叶…

【Python】MacBook M系列芯片Anaconda下载Pytorch,并开发一个简单的数字识别代码(附带踩坑记录)

文章目录 配置镜像源下载Pytorch验证使用Pytorch进行数字识别 配置镜像源 Anaconda下载完毕之后&#xff0c;有两种方式下载pytorch&#xff0c;一种是用页面可视化的方式去下载&#xff0c;另一种方式就是直接用命令行工具去下载。 但是由于默认的Anaconda走的是外网&#x…

3D Gaussian Splatting代码中的forward和backward两个文件代码解读

3dgs代码前向传播部分 先来讨论一下glm&#xff0c;因为定义变量的时候用到了这个。 glm的解释 glm 是指 OpenGL Mathematics&#xff0c;这是一个针对图形编程的数学库。它的全称是 OpenGL Mathematics (GLM)&#xff0c;主要用于 OpenGL 的开发。这个库是基于 C 的模板库&…

heic格式转化jpg,手把手教你将heic转换成jpg【办公必备】

一、什么是heic heic格式是一种高效的图片格式&#xff0c;它可以在较小的文件大小下提供高质量的图片。 二、如何打开heic 然而&#xff0c;这种图片因其格式的特殊性&#xff0c;在实际应用中仍存在一些问题&#xff1a;压缩效果可能不够理想&#xff0c;一些老旧的软件和设…

墨烯的C语言技术栈-C语言基础-003

三.数据类型 1.char // 字符数据型 2.short // 短整型 3.int // 整型 4.long // 长整型 5.long long // 更长的整型 6.float // 单精度浮点数 7.double // 双精度浮点数 为什么写代码? 为了解决生活中的问题 购物,点餐,看电影 为什么有这么多类型呢? 因为说的话都是字符型…

Ubuntu下反弹shell的思考

目录 Ubuntu的命令执行环境 bash (Bourne Again SHell): sh (Bourne SHell): dash (Debian Almquist SHell): 它们之间的关系&#xff1a; 可能遇到的问题 一、脚本权限问题 二、命令执行环境(shell解释器)问题 如何解决&#xff1f; 1.修改/bin/sh软连接的指向为bas…

什么美业门店管理系统好用?2024美业收银系统软件排名分享

美业SAAS系统在美容、美发、美甲等行业中十分重要&#xff0c;这种系统为美业提供了一种数字化解决方案&#xff0c;帮助企业更高效地管理业务和客户关系。 美业门店管理系统通常提供预约管理、客户管理、库存管理、报表生成等一系列功能&#xff0c;以满足美容院、美发沙龙等…