C++学习记录——이십팔 C++11(4)

news2024/11/24 12:53:55

文章目录

  • 包装器
    • 1、functional
    • 2、绑定


这一篇比较简短,只是因为后要写异常和智能指针,所以就把它单独放在了一篇博客,后面新开几篇博客来写异常和智能指针

包装器

1、functional

包装器是一个类模板,对可调用对象类型进行再封装适配,可调用对象,比如函数指针,lambda等。包装器的头文件是functional。

template <class T> function;
template <class Ret, class... Args>
class function<Ret(Args...)>
模板参数说明:
Ret:被调用函数的返回类型
Args...:被调用函数的形参

实际使用

int f(int a, int b)
{
	cout << "f" << endl;
	return a + b;
}

struct Functor
{
public:
	int operator() (int a, int b)
	{
		cout << "Functor" << endl;
		return a + b;
	}
};

int main()
{
	//int(*pf1)(int, int) = f;函数指针
	function<int(int, int)> f1 = f;
	function<int(int, int)> f2 = Functor();
	function<int(int, int)> f3 = [](int a, int b) {
		cout << "lambda" << endl;
		return a + b; 
	};
	cout << f1(1, 2) << endl;
	cout << f2(10, 20) << endl;
	cout << f3(100, 200) << endl;
	return 0;
}

三个int,第一个是函数返回值类型,后两个是参数类型。包装起包装起来的就可以传给模板参数

	map<string, function<int(int, int)>> opFuncMap;
	opFuncMap["函数指针"] = f1;
	opFuncMap["仿函数"] = Functor();
	opFuncMap["lambda"] = [](int a, int b) {
		cout << "lambda" << endl;
		return a + b;
	};
	cout << opFuncMap["lambda"](1, 2) << endl;

看一个题

逆波兰表达式求值

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

有效的算符为 ‘+’、‘-’、‘*’ 和 ‘/’ 。
每个操作数(运算对象)都可以是一个整数或者另一个表达式。
两个整数之间的除法总是 向零截断 。
表达式中不含除零运算。
输入是一个根据逆波兰表示法表示的算术表达式。
答案及所有中间计算结果可以用32位整数表示。

在这里插入图片描述

在这里插入图片描述

之前的写法

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();
                switch(str[0])
                {
                    case '+':
                        st.push(left+right);
                        break;
                    case '-':
                        st.push(left-right);
                        break;
                    case '*':
                        st.push(left*right);
                        break;
                    case '/':
                        st.push(left/right);
                        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)>> opFuncMap = 
        {
            {"+", [](int a, int b){return a + b; }},
            {"-", [](int a, int b){return a - b; }},
            {"*", [](int a, int b){return a * b; }},
            {"/", [](int a, int b){return a / b; }}
        };//这里就是map的初始化,用C++11的列表初始化
        for(auto str : tokens)
        {
            if(opFuncMap.count(str))
            {
                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();
                st.push(opFuncMap[str](left, right));
            }
            else
            {
                st.push(stoi(str));
            }
        }
        return st.top();
    }
};

包装器也可以包装成员函数。

class Plus
{
public:
	static int plus1(int a, int b)
	{
		return a + b;
	}
	double plus2(double a, double b)
	{
		return (a + b) * _rate;
	}
private:
	int _rate = 2;
};

int main()
{
class Plus
{
public:
	Plus(int rate = 2)
		:_rate(rate)
	{}
	static int plus1(int a, int b)
	{
		return a + b;
	}
	double plus2(double a, double b)
	{
		return (a + b) * _rate;
	}
private:
	int _rate = 2;
};

int main()
{
	function<int(int, int)> f1 = Plus::plus1;
	function<int(Plus, double, double)> f2 = &Plus::plus2;
	cout << f1(1, 2) << endl;
	cout << f2(Plus(), 20, 20) << endl;
	Plus p1(3);
	cout << f2(p1, 20, 20) << endl;
    return 0;
}

静态成员函数可以直接调用,而非静态的需要在第一个位置加上类名,因为有this指针,然后后面的Plus前加上&,静态函数也可以加上这个&,使用这个函数的时候,非静态需要在第一个参数位置放上类的对象,可以是匿名对象,如果在声明f2时,传的是*Plus,那么下面调用时就必须传对象的地址,所以就不能传匿名对象的地址,因为右值无法取地址。

包装器本质上是仿函数,f1,f2,f3就是对象,然后调用operator(),传过去参数,然后operator()再去调用对应函数,传类的对象就用对象来调用,传指针就指针来调用。

2、绑定

绑定是一个函数模板,用来调整参数。绑定是一个通用的函数适配器,接受一个可调用对象,可调用对象就是三个,函数指针、lambda、仿函数,生成一个新的可调用对象来适配。

bind函数第一个参数是一个万能引用,左右值都可传,然后后面的是占位符,_1表示第一个参数,_2表示第二个参数,以此类推,这些占位符是一个placeholders空间里。

int Print(int a, int b)
{
	cout << a << " ";
	cout << b << endl;
}

int main()
{
	Print(10, 20);
	auto RP = bind(Print, placeholders::_2, placeholders::_1);
	RP(10, 20);//再次调用就换了顺序了。
	return 0;
}

如果bind写着_1在_2前面,那就没换顺序,要换顺序占位符就得对应着写。bind函数会返回一个对象,我们可以用auto来推演类型,还可以用function<void(int, int)>。实际调用的还是Print,不过适配器就是套了一个壳。

绑定真正有用的是改变参数个数

用这段代码做例子

class Sub
{
public:
	Sub(int rate)
		:_rate(rate)
	{}

	int func(int a, int b)
	{
		return (a - b) * _rate;
	}
private:
	int _rate;
};

class Solution {
public:
	int evalRPN(vector<string>& tokens) {
		stack<int> st;
		map<string, function<int(int, int)>> opFuncMap =
		{
			{"+", [](int a, int b) {return a + b; }},
			{"-", [](int a, int b) {return a - b; }},
			{"*", [](int a, int b) {return a * b; }},
			{"/", [](int a, int b) {return a / b; }}
		};//这里就是map的初始化,用C++11的列表初始化
		for (auto str : tokens)
		{
			if (opFuncMap.count(str))
			{
				int right = st.top();
				st.pop();
				int left = st.top();
				st.pop();
				st.push(opFuncMap[str](left, right));
			}
			else
			{
				st.push(stoi(str));
			}
		}
		return st.top();
	}
};

int main()
{
	function<int(Sub, int, int)> fSub = &Sub::func;
	fSub(Sub(1), 10, 20);
	return 0;
}

这是上面包装器的写法。这样的写法无法给opFuncMap传fSub对象,因为参数个数不一致,这时候就是绑定的作用体现了。

	function<int(int, int)> fSub = bind(&Sub::func, Sub(1), placeholders::_1, placeholders::_2);
	fSub(10, 20);

把Sub(1)对象显式地传给func函数,顺序没有变,只是第一个参数显示传,剩下两个就从_1开始排顺序。也可以对其他参数来绑定。

	function<int(int, int)> fSub = bind(&Sub::func, placeholders::_1, 10, placeholders::_2);
	fSub(Sub(1), 20);

本篇gitee

结束。

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

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

相关文章

安全学习DAY20_自动化工具项目武器库介绍

信息打点-自动化工具 文章目录 信息打点-自动化工具本节思维导图&概述 各类红蓝队优秀工具项目集合&#xff1a;All-Defense-Tool 自动化-武器库部署F8x 自动化信息搜集-网络空间AsamF 自动化信息搜集-企查信息ENScan 自动化信息搜集-综合架构-ARL&NemoARL灯塔Nemo_Go …

MySQL 特殊语法时间格式以及Greadb连接

一、时间语法 DATE_FORMAT和to_char() select to_char(now(),%Y-%m-%d %H:%i:%s) from dual; select DATE_FORMAT(now(),%Y-%m-%d %H:%i:%s) from dual; 2.to_date() 和STR_TO_DATE(#{date},%Y-%m-%d ) select to_date(now(),yyyy-mm-dd hh24:mi:ss) from dual;

null和undefined区别

1.undefined&#xff0c;表示无值。 比如下面场景&#xff1a; a. 变量被声明了&#xff0c;但是没有被赋值&#xff1b; b. 调用函数的时候&#xff0c;应该给函数传参却没有给函数传这个参数打印出来就是 undefined&#xff1b; c. 访问一个对象中没有的属性&#xff1b;…

Blender给一个对象添加多个动画

最近在做一个类似元宇宙的项目&#xff0c;需要使用3D建模软件来给3D模型添加动画&#xff0c;3D建模软件选择Blender&#xff08;因为开源免费…&#xff09;&#xff0c;版本: V3.5 遇到的需求是同一个对象要添加多个动画&#xff0c;然后在代码里根据需要调取动画来执行。本…

飞腾CPU FT-2000/4 uboot下PHY调试记录

一、环境说明 板子是FT-2000/4的开发板: 固件版本: ft-2004c_u-boot-v2-Ver0.3_202112231001.tar.gz ft2004c_v2.06_image_fix.rar 二、调试命令说明 调试PHY主要用到的命令是mii,先查看下可用的命令: mii device,缩写mii dev,查看网络控制器mac。mii device,缩写mi…

【C++】初始化列表

前言&#xff1a;这个知识点的细节比较多&#xff0c;且有些细节不太容易理解&#xff0c;要做好准备哟&#x1f47b; Ⅰ.构造函数的不完美&#x1f62d; 初始化列表&#xff0c;顾名思义&#xff0c;用列表一样的格式将其初始化。 &#x1f914;奇怪啊&#xff0c;构造函数的…

DOCKER 部署 webman项目

# 设置基础镜像 FROM php:8.2-fpm# 安装必要的软件包和依赖项 RUN apt-get update && apt-get install -y \nginx \libzip-dev \libpng-dev \libjpeg-dev \libfreetype6-dev \&& rm -rf /var/lib/apt/lists/*# 安装 PHP 扩展 RUN docker-php-ext-configure gd …

Uniapp笔记(八)初识微信小程序

一、微信小程序基本介绍 1、什么是微信小程序 微信小程序简称小程序&#xff0c;英文名Mini Program&#xff0c;是一种不需要下载安装即可使用的应用&#xff0c;它实现了应用“触手可及”的梦想&#xff0c;用户扫一扫或搜一下即可打开应用 小程序是一种新的开放能力&#…

嵌入式学习之指针

今天周天&#xff0c;主要对linux系统编程的知识进行了学习&#xff0c;但是很多精华还是没有学到位&#xff0c;重点的学习内容是把linux 中open,write,lseek,close的相关操作进行了学习。其次再次把函数指针&#xff0c;数组指针&#xff0c;指针函数&#xff0c;指针数组进行…

线性代数的学习和整理13: 函数与向量/矩阵

目录 1 函数与 向量/矩阵 2 函数的定义域&#xff0c;值域&#xff0c;到达域 3 对应关系 1 函数与 向量/矩阵 下面两者形式类似&#xff0c;本质也类似 函数的&#xff1a; axy &#xff0c;常规函数里&#xff0c;a,x,y 一般都是单个数矩阵&#xff1a; AXY &a…

[管理与领导-54]:IT基层管理者 - 扩展技能 - 1 - 时间管理 -1- 时间管理的基本理念和五大原则

前言&#xff1a; 管理学大师彼得 德鲁克曾说过:“不能管理时间&#xff0c;便什么也不能管理” 。论语中说&#xff1a;逝者如斯 夫!不舍昼夜。时间对任何一个人来说都是十分重要的&#xff0c;对于惜时如金的管理者来说更是如此。 时间也是一种资源&#xff0c;对所有的人…

TIM输入捕获笔记 (计算编码电机的频率和占空比)

1. 输入捕获简介 IC (Input Capture) 输入捕获输入捕获模式下&#xff0c;当通道输入引脚出现指定电平跳变时&#xff0c;当前CNT的值将被锁存到CCR中&#xff0c;可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数每个高级定时器和通用定时器都拥有4个输入捕获…

Docker网络原理及案例详解

文章目录 简介Docker网络产生的过程Docker network的作用网络模式网络模式---bridge网络模式---host网络模式---none 自定义网络 简介 Docker网络实现容器之间通信和连接外部网络的功能,主要的网络连接方式有桥接网络&#xff08;Bridge Network、主机网络&#xff08;Host Ne…

【LeetCode75】第三十九题 二叉树的右视图

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一棵二叉树&#xff0c;让我们返回站在二叉树右边从上到下看到的节点。 那实际上就是要我们对二叉树进行层序遍历&#xff0c…

CS144(2023 Spring)Lab 0:networking warmup(环境搭建 webget bytestream)

文章目录 前言其他笔记相关链接 1. Set up GNU/Linux on your computer2. Networking by hand3. Writing a network program using an OS stream socket3.1 Linux配置3.2 C规范3.3 Writing webget3.3.1 实现3.3.2 测试 4. An in-memory reliable byte stream4.1 思路分析4.2 代…

《C和指针》笔记14: 作用域和存储类型总结(例子说明)

文章目录 题目答案解释总结 本文是作用域和存储类型的总结&#xff0c;以一个例子来说明&#xff0c;如果不看解释可以很直接地回答每一条语句的作用域和存储类型&#xff0c;那么说明已经很熟练地掌握这个知识点了。 关于作用域和存储类型可以参考我前面的博客&#xff1a; …

LeetCode-56-合并区间

题目描述&#xff1a; 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 可以使用 LinkedList&#xff0c;…

Cadence+硬件每日学习十个知识点(46)23.8.26 (运算放大器)

文章目录 1.电压跟随器的输入和输出是一样的&#xff0c;但是输入的是电压带有高阻抗&#xff0c;输出的电压带有低阻抗。2.比较器的迟滞&#xff08;这个电阻&#xff09;3.运放的压摆率4.运放-轨到轨5.输入失调电压Vos&#xff08;选一个低的器件就行&#xff0c;对于5V&…

Batbot电力云平台在智能配电室中的应用

智能配电室管理系统是物联网应用中的底层应用场景&#xff0c;无论是新基建下的智能升级&#xff0c;还是双碳目标下的能源管理&#xff0c;都离不开智能配电运维对传统配电室的智慧改造。Batbot智慧电力&#xff08;运维&#xff09;云平台通过对配电室关键电力设备部署传感器…

【学习笔记】求解线性方程组的G-S迭代法

求解线性方程组的G-S迭代法 // 运行不成功啊function [x,k,index] Gau_Seid(A,b,ep,it_max) % 求解线性方程组的G-S迭代法&#xff0c;其中 % A为方程组的系数矩阵 % b为方程组的右端项 % ep为精度要求&#xff0c;省缺为1e-5 % it_max为最大迭代次数&#xff0c;省缺为100 % …