C++ STL:适配器 Adapter
文章目录
- 1、容器适配器
- 1.1、stack
- 1.2、queue
- 1.3、priority_queue
- 2、迭代器适配器
- 2.1、插入迭代器
- 2.2、反向迭代器
- 2.3、流迭代器
- 3、函数适配器
- 3.1、* bind
- bind 使用方法
- bind 简化原理
- 3.2、mem_fn
适配器就是接口,对容器、迭代器、算法进行包装,但其实质还是容器、迭代器和算法,只是不依赖于具体的标准容器、迭代器和算法类型。概念源于设计模式中的适配器模式:将一个类的接口转化为另一个类的接口,使原本不兼容而不能合作的类,可以一起运作。
容器适配器可以理解为容器的模板,迭代器适配器可理解为迭代器的模板,算法适配器可理解为算法的模板。
1、容器适配器
应用于容器,容器适配器包括:stack queue priority_queue
1.1、stack
stack 容器适配器,是 FILO
(先进后出)的数据结构,底层容器deque
,从容器的尾部(栈顶)推弹元素
template<class T, class Container = std::deque<T>> class stack;
1.2、queue
queue 容器适配器,是 FIFO
(先进先出)数据结构,底层容器 deque
,从容器尾部(队尾)推入元素,从容器头部(队头)弹出元素。
template<class T, class Container = std::deque<T>> class queue;
1.3、priority_queue
优先队列是容器适配器,提供常数时间的最值元素查找,对数时间的插入和删除。
- 底层容器
vector
- 元素放入优先队列时,采用堆排序自动调整顺序
- 针对自定义类类型,需要重载比较方式
class compare
- 默认情况下,
std::less<T>
,用的是小于符号,产生的是大顶堆。否则是小顶堆std::greater<T>
template<class T, class Container = std::vector<T>, class Compare = std::less<typename Container::value_type>> class priority_queue;
2、迭代器适配器
应用于迭代器。
- 插入迭代器:
front_insert_iterator
,back_insert_iterator
,insert_iterator
- 反向迭代器:
reverse_iterator
- 流迭代器:
ostream_iterator
,istream_iterator
2.1、插入迭代器
front_insert_iterator
:在容器的尾部插入新元素,底层调用push_back()
back_insert_iterator
:在容器的头部插入新元素,底层调用push_front()
insert_iterator
:在容器指定位置插入新元素,底层调用insert()
容器使用插入迭代器时,底层必须实现对应的方法。
STL 为了提升使用的便利性,提供三个相应的函数,内部封装的是相应的插入迭代器
front_inserter
back_inserter
inserter
测试1:front_inserter | front_insert_iterator
,输出结果:5 4 3 2 1 11 12 13
vector<int> nums{1, 2, 3, 4, 5};
list<int> ls{11, 12, 13};copy(nums.begin(), nums.end(), front_inserter(ls));
// copy(nums.begin(), nums.end(), front_insert_iterator<list<int>>(ls));copy(ls.begin(), ls.end(), ostream_iterator<int>(cout, " "));
cout << endl;
测试2:back_insert_iterator|
,输出结果:11 12 13 1 2 3 4 5
vector<int> nums{1, 2, 3, 4, 5};
list<int> ls{11, 12, 13};copy(nums.begin(), nums.end(), back_inserter(ls));
// copy(nums.begin(), nums.end(), back_insert_iterator<list<int>>(ls));copy(ls.begin(), ls.end(), ostream_iterator<int>(cout, " "));
cout << endl;
测试3:insert_iterator | inserter
,输出结果:11 1 2 3 4 5 12 13
vector<int> nums{1, 2, 3, 4, 5};
list<int> li {11, 12, 13};
auto it = li.begin();
++it;copy(nums.begin(), nums.end(), inserter<list<int>>(li, it));
// copy(nums.begin(), nums.end(), insert_iterator<li<int>>(li, it));copy(li.begin(), li.end(), ostream_iterator<int>(cout, " "));
cout << endl;
2.2、反向迭代器
reverse_iterator
,将迭代器的方向进行逆转,实现逆序遍历,底层是双向迭代器
测试:逆序输出结果:5 4 3 2 1
vector<int> nums{1, 2, 3, 4, 5};for (reverse_iterator rit = nums.rbegin(); rit != nums.rend(); ++rit) {cout << *rit << " ";
}
2.3、流迭代器
ostream_iterator | inputIterator
,可以将迭代器绑定到某个 iostream
对象上,拥有输入输出功能。以此为基础,稍加修改,就可以适用于任何输入或输出装置上。例如:绑定到磁盘的某个目录上。原理就是把输入输出流当作容器(输入输出流拥有缓冲区),容器的访问需要迭代器。
测试1:ostream_iterator
vector<int> nums{1, 2, 3, 4, 5};// 将标准输出当成是容器,容器的访问就需要迭代器
// 每次写操作后,写入可选的分隔符。
// std::ostream_iterator<int> osi(cout, " ");
// std::copy(nums.begin(), nums.end(), osi);copy(nums.begin(), nums.end(), ostream_iterator<int>(cout, " "));
测试2:istream_iterator
vector<int> nums;
// 将标准输入流当成是容器,容器的访问就需要迭代器
istream_iterator<int> isi(std::cin);// 匿名的 istream_iterator 对象,表示迭代器结束的位置,详见构造函数源码
// 快捷键: ctrl + d 表示输入结束
// 问题:nums 还没有申请空间,所以插入新的元素时,会出现 bug
// copy(isi, istream_iterator<int>(), nums.begin()); // error// 插入元素时,需要使用插入迭代器来完成
// back_insert ==> 调用到push_back完成元素的添加
copy(isi, istream_iterator<int>(), std::back_inserter(nums));
3、函数适配器
应用于仿函数。灵活度很高,可以配接,配接,再配接。通过它们之间的绑定、组合、修饰能力,可以无限制创造出各种可能的表达式。
包括
- 绑定
bind
- 否定
negate
- 组合
compose
- 修饰:通过修饰普通函数、成员函数,使之成为仿函数
3.1、* bind
bind 函数绑定多个实参到函数对象,函数原型:
/*
返回值:函数对象
参数:
- f: 可调用 (Callable) 对象(函数对象、指向函数指针、函数引用、指向成员函数指针或指向数据成员指针)
- args: 要绑定的参数列表,未绑定参数为命名空间 std::placeholders 的占位符 _1, _2, _3...所替换
*/
template< class F, class... Args >
/*unspecified*/ bind( F&& f, Args&&... args );template< class R, class F, class... Args >
/*unspecified*/ bind( F&& f, Args&&... args );
bind 使用方法
bind 绑定类型
- 绑定普通函数。
- 绑定成员函数。成员函数隐含 this 指针,必须显示绑定
- 绑定数据成员。
若不想提前绑定参数,则使用占位符,占位符本身所在的位置是形参的位置,占位符的数字代表实参传递时候的位置,即函数调用时绑定实参列表中的对应实参位置。没有绑定的实参是无效参数。
bind 绑定参数采用值传递。bind 绑定参数采用值传递。
例如:
#include <functional>
#include <iostream>
using std::cout;
using std::endl;
using std::bind;
using namespace std::placeholders;int add(int x, int y) {cout << "int add(int,int) = " << endl;cout << "(" << x << ", " << y << ")" << endl;return x + y;
}struct MyTest {int add(int x, int y) { cout << "MyTest::add(int,int)" << endl;return x + y + data;}int data = 1000; // C++11 特性
};void func(int n1, int n2, int n3, const int & n4, int n5) {cout << "(" << n1 << "," << n2 << "," << n3 << "," << n4 << "," << n5 << ")" << endl;
}void func(int n1, int n2, int n3, const int & n4, int n5) {cout << "(" << n1 << "," << n2 << "," << n3 << "," << n4 << "," << n5 << ")" << endl;
}// 1、bind 绑定普通函数
void test0() {// 1.1、绑定实参到函数对象,实参与形参必须一一对应auto f = std::bind(add, 1, 2);cout << f() << endl << endl;// 1.2、若不想提前绑定参数,使用占位符,表示调用时绑定实参列表的位置// 1.2.1、使用 bind 绑定 add 函数对象: arg1 = 1, 占位符 _1auto f1 = std::bind(add, 1, _1); // 占位符 _1 表示绑定的是调用时实参列表的第一个位置, 即 (10, 11, 12) 中的 10// 输出结果:(1, 10), 11,12 为无效参数cout << f1(10, 11, 12) << endl; // 等价于 f1(10)// 1.2.2、使用 bind 绑定 add 函数对象: arg1 = 1,占位符 _2auto f2 = std::bind(add, 1, _2);// 占位符 _1 表示绑定的是调用时实参列表的第2个位置, 即 (10, 11, 12) 中的 11// 输出结果:(1, 11). 10, 12 为无效参数cout << f2(10, 11, 12) << endl;
} // 2、bind 绑定成员函数和数据成员
void test1() {MyTest mytest;// 2.1、绑定成员函数// 显示绑定 this 指针,需要保证其生命周期存在auto f = std::bind(&MyTest::add, &mytest, 1, 2);cout << f() << endl; // 输出:3auto f1 = std::bind(&MyTest::add, &mytest, _1, 2);cout << f1(10) << endl; // 输出 12auto f2 = std::bind(&MyTest::add, mytest, _1, _1);cout << f2(10, 20) << endl; // 输出 20// 2.2、绑定数据成员auto f3 = std::bind(&MyTest::data, mytest);cout << f3() << endl; // 输出 1000
}// 3、bind 绑定采用的是值传递
void test2() { int n = 100;// 值传递,传递对象时,会对对象本身进行复制auto f = std::bind(func, _2, 10, _1, std::cref(n), n);n = 111; // 实参1对应形参_1,实参2对应形参_2,值传递 n 不变f(1, 2); // 输出结果:(2,10,1,111,100)
}int main(void) {test0(); // test1();// test2(); return 0;
}
bind 简化原理
内部生成 Binder
类,把要绑定的函数和参数提存储起来,并重载函数调用运算符
bind绑定普通函数
#include <functional>
#include <iostream>
using std::cout;
using std::endl;int (* f)(int,int); // 声明一个函数类型变量 f
typedef int(*Function)(int,int); // 声明一个函数类型int add(int x, int y) {int number ;cout << "int add(int,int)" << endl;cout << "(" << x << ", " << y << ")" << endl;return x + y;
}int multiply(int x, int y) { return x * y;
}// 1、C 语言的多态机制:函数指针
// C 语言通过函数指针体现多态
void test0() {// Function 是一个类型,func 是一个对象(变量)// 函数 add 和 multiply 是常量。编译完成后,函数入口地址就确定了Function func;// 1、注册回调函数 // 2、执行回调函数 func = add; cout << func(1, 2) << endl;func = multiply;cout << func(3, 4) << endl;
}// 类比:std::bind 绑定后,返回的函数对象
struct Binder {Binder(int(*p)(int,int), int x, int y): pFunc(p), a(x), b(y) {}int operator()() {return pFunc(a, b);}int (*pFunc)(int,int);int a;int b;
};struct Binder mybind(int(*p)(int,int), int x, int y) {return Binder(p, x, y);
}// 2、std::bind 绑定普通函数
void test1() {auto f = std::bind(add, 1, 2);f();Binder binder(add, 1, 2);binder();auto f2 = mybind(add, 1, 2);f2();
}
bind 绑定成员函数
struct Mytest {int add(int x, int y) {cout << "Mytest::aad(int,int)" << endl;return x + y;}
};struct Mybinder {Mybinder(int(Mytest::*f)(int,int), Mytest t, int x, int y): p(f), test(t), a(x), b(y) {}int operator()() {return (test.*p)(a, b);}int (Mytest::*p)(int,int);Mytest test;int a;int b;
};// 2、std::bind 绑定成员函数
void test2() {Mytest test;Mytest * ptest = &test;// 声明一个成员函数指针时,需要指定类作用域int (Mytest::*p)(int,int) = &Mytest::add;// 成员函数指针的调用形式// 2.1、通过对象调用成员函数指针, 采用 .*cout << (test.*p)(1, 2) << endl;// 2.2、通过对象的指针调用成员函数指针, 采用 ->*cout << (ptest->*p)(1, 2) << endl;
}
3.2、mem_fn
成员函数绑定器
// 绑定成员函数,删除质数元素,并打印
nums.erase(remove_if(nums.begin(), nums.end(), mem_fn(&Number::isPrime)), nums.end());
std::for_each(nums.begin(), nums.end(), mem_fn(&Number::print));
相关文章:
C++ STL:适配器 Adapter
文章目录1、容器适配器1.1、stack1.2、queue1.3、priority_queue2、迭代器适配器2.1、插入迭代器2.2、反向迭代器2.3、流迭代器3、函数适配器3.1、* bindbind 使用方法bind 简化原理3.2、mem_fn适配器就是接口,对容器、迭代器、算法进行包装,但其实质还是…...
防抖和节流
防抖和节流的区别?防抖:触发高频事件后n 秒内 函数只会执行一次,如果n秒内 高频事件在在次触发,则会重新计算节流:高频事件触发,但在n 秒内 只会执行一次,所以节流会稀释函数的执行频率下面就是…...
vue3 微信扫码登录及获取个人信息实现的三种方法
一、流程: 微信提供的扫码方式有两种,分别是: 跳转二维码扫描页面 内嵌式二维码根据文档我们可以知道关于扫码授权的模式整体流程为: 1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站&…...
Java8 新特性强大的Stream API
一、Stream API 说明 Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API。 Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Ja…...
day22_IO
今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、作业 二、缓冲流 三、字符流 四、缓冲字符流 五、匿名内部类 零、 复习昨日 File: 通过路径代表一个文件或目录 方法: 创建型,查找类,判断类,其他 IO …...
第三十八章 linux-并发解决方法二(信号量)
第三十八章 linux-并发解决方法二(信号量) 文章目录第三十八章 linux-并发解决方法二(信号量)信号量的定义DOWN操作UP操作相对于自旋锁,信号量的最大特点是允许调用它的线程进入睡眠状态这意味着试图获得某一信号的进程…...
数据结构-考研难点代码突破(C++实现树型查找 - B树插入与遍历,B+树基本概念)
数据结构(C)[B树(B-树)插入与中序遍历,效率分析]、B树、B*树、B树系列应用 文章目录1. B树B树的插入与删除流程2. B树(MySQL)3. B树与B树对比4. C实现B树插入,中序遍历1. B树 B树类…...
Python可视化界面编程入门
Python可视化界面编程入门具体实现代码如所示: (1)普通可视化界面编程代码入门: import sys from PyQt5.QtWidgets import QWidget,QApplication #导入两个类来进行程序界面编程if __name__"__main__":#创建一个Appl…...
基于Java+SpringBoot+Vue前后端分离书店购书系统设计与实现
博主介绍:✌全网粉丝3W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战✌ 博主作品:《微服务实战》专栏是本人的实战经验总结,《Spring家族及…...
Android:截屏/视频截图
需求描述 实现截取Android应用当前界面的功能,需包含界面中视频(此博客的参考代码以存储在设备本地的视频为例,未检验在线视频的情况)当前的播放帧截图。 调研准备 首先应用需要获取设备存储的读写权限,需要在Andro…...
leecode-C语言实现-28. 找出字符串中第一个匹配项的下标
一、题目给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。示例 1:输入:haystack …...
使用 Postman 实现 API 自动化测试
目录:导读 背景介绍 名词解析 使用说明 执行 API 测试 集成 CI 实现 API 自动化测试 写在最后 背景介绍 相信大部分开发人员和测试人员对 postman 都十分熟悉,对于开发人员和测试人员而言,使用 postman 来编写和保存测试用例会是一种比…...
k8s环境jenkins发布vue项目指定nodejs版本
k8s环境jenkins发布vue项目指定nodejs版本1、背景2、分析3、解决方法3.1、 找到配置镜像位置3.2、 制作新镜像3.3、 推送镜像到私有仓库3.4、 修改配置文件1、背景 发布一个前端项目,它需要nodejs 16.9.0版本支持,而kubesphere 3.2.0集成的jenkins 的镜…...
我应该把毕业设计做到什么程度才能过关?
本篇博客包含了狗哥多年职业生涯对于软件项目的一丢丢理解,也讲述了对于大学生毕业设计的一些理解。如果你还是懵懵懂懂就要离开学校了,被老师告知不得不做出一套毕业设计的时候,希望你可以看到这篇博客,让你有点头绪,…...
力扣-合作过至少三次的演员和导演
大家好,我是空空star,本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目:1050. 合作过至少三次的演员和导演二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运…...
【 PMU】信号生成、采样、分割、估计器应用和误差计算(Matlab代码实现)
👨🎓个人主页:研学社的博客💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密…...
电子技术——AB类输出阶的偏置
电子技术——AB类输出阶的偏置 下面我们介绍两种AB类输出阶的偏置的方法。 使用二极管偏置 下图展示了电流源 III 加两个二极管的偏置方法: 因为输出阶需要大功率输出,因此输出推挽三极管可能是几何体积比较大的晶体管。对于二极管来说,并不…...
元宇宙营业厅,数字技术融合,赋能实体经济
在我国数字经济与虚拟服务市场规模扩大下,元宇宙营业厅强势来袭,从多场景、多内容,深耕高效协同的特色功能,基于多元化、灵活的交互体验,更大程度上解决线上业务办理抽象繁琐,线下业务办理的时空受限、业务…...
MySql面试精选—分库分表
目录 1、分库分表使用场景 2、常见的分库分表方案 3、常用的分库分表中间件...
Spring上下文生命周期
基于入口来分析 import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;Configuration ComponentScan public cl…...
GitHub 标星 15w,如何用 Python 实现所有算法?
学会了 Python 基础知识,想进阶一下,那就来点算法吧!毕竟编程语言只是工具,结构算法才是灵魂。 新手如何入门 Python 算法? 几位印度小哥在 GitHub 上建了一个各种 Python 算法的新手入门大全。从原理到代码…...
LeetCode 700. 二叉搜索树中的搜索
LeetCode 700. 二叉搜索树中的搜索 难度:easy\color{Green}{easy}easy 难度:middle\color{orange}{middle}middle 难度:hard\color{red}{hard}hard 题目描述 给定二叉搜索树(BST)的根节点 rootrootroot 和一个整数值…...
【数据结构】树与二叉树
目录 1、树的概念及结构 1.1、概念 1、树的特点 2、树与非树 1.2、概念 (重要) 1.3、树的表示形式 2、二叉树(重点) 2.1、概念 2.2、二叉树的特点 2.3、两种特殊的二叉树 1、满二叉树 2、完全二叉树 2.4、二叉树的性…...
Stress压力工具的部署及使用
Stress压力工具的部署及使用 下载地址:wget https://fossies.org/linux/privat/old/stress-1.0.5.tar.gz 1.部署 进入目录执行./autogen.sh [rootiZ2ze1pj93eyq389c2ppi5Z stress-1.0.5]# ./autogen.sh ps:如果执行过程中缺包,安装对应的…...
[蓝桥杯 2020 省 AB3] 乘法表
题目描述九九乘法表是学习乘法时必须要掌握的。在不同进制数下,需要不同的乘法表。例如, 四进制下的乘法表如下所示:1*11 2*12 2*210 3*13 3*212 3*321请注意,乘法表中两个数相乘的顺序必须为样例中所示的顺序,不能随意交换两个乘…...
Python基础知识
基础知识 基础知识包括输入输出、变量、数据类型、表达式、运算符这5个方面。 1.输入输出 Python有很多函数,后面我们会细讲,但这里先将两个最基本的函数:输入和输出。 输出函数print(),在前面我们已经用过了,语法…...
FME案例实战教程:聚焦实战应用,摆脱思路束缚,您值得拥有
一、教程链接(一)FME案例实战教程链接1.FME案例实战教程(完整版) ☚强烈推荐☚2.FME案例实战教程(A组)3.FME案例实战教程(B组)4.FME案例实战教程(C组)&#…...
【JavaScript】根据元素内容遍历元素的方案
▒ 目录 ▒🛫 导读需求1️⃣ jQuery2️⃣ XPATH(document.evaluate)3️⃣ 原生js(querySelectorAll & Array)🛬 文章小结📖 参考资料🛫 导读 需求 因业务需要,根据元…...
kafka全解
目录Kafka概述定义消息队列目录结构分析传统消息队列的应用场景消息队列的两种模式点对点模式发布/订阅模式Kafka基础架构Kafka快速入门安装部署集群规划集群部署集群启停脚本Kafka命令行操作Kafka基础架构主题命令行操作生产者命令行操作消费者命令行操作kafka可视化工具Kafka…...
(三)随处可见的LED广告屏是怎么工作的呢?接入GUI
续上文,本篇我们将尝试接入一个GUI来控制点阵屏。在前两篇中,我们相继介绍了点阵屏的控制原理,以及如何让点阵屏按照我们所想的进行显示。本篇将在此基础上接入一个GUI,使点阵屏的控制更加优雅。限于阅读体验和展示效果࿰…...
建设网站论文/怎样优化网站排名靠前
COORDX:使用分裂MLP架构加速隐式神经表示 COORDX ACCELERATING IMPLICIT NEURAL REPRESENTATION WITH A SPLIT MLP ARCHITECTURE 最近,多层感知器(MLP)隐式神经表示在各种各样的任务中得到了突出的应用,例如新的视图合…...
wordpress付费阅读插件/网站运营主要做什么工作
转载http://www.cnblogs.com/jianc/archive/2013/02/26/2932965.html 记在前面: 以前刚开始的时候, 想实现某某功能, 跑百度谷歌, 查Qt助手, 好不容易实现目标功能; 但当时并没有做任何的笔记; 或者只记录几个比较深刻的知识; 后来要再次实现那些功能, 又得重新花一大半时间去搜…...
找事做搜索网站/企业培训课程有哪些内容
在工作中,我经常会用阿里的IconFont图标库,今天发现一个之前没怎么注意到的问题。 首先IconFont给我们提供了三种引用图标的方式 unicode引用 unicode是字体在网页端最原始的应用方式,特点是: 兼容性最好,支持ie6,及所…...
东光县建设局网站/杭州百度推广代理商
原始地址:http://rockhooray.blog.51cto.com/938613/813119 Linux网口绑定 通过网口绑定(bond)技术,可以很容易实现网口冗余,负载均衡,从而达到高可用高可靠的目的。 前提约定: 2个物理网口分别是:eth0,eth1 绑定后的…...
深圳公司网站建设设计/如何做个网站推广自己产品
我是一名初学者,正在构建一个带按钮和滚动条的简单窗口.当我编译我的代码时,我的按钮上的文字被删除了一个省略号,图像图标没有显示.我试过在eclipse和NetBeans中编译它.为了解决我试过的问题.setMargin(new Insets(0, 0, 0, 0));.setPreferedSizeadding padding (I forgot the…...
武汉手机网站制作公司/宁波seo外包
C11 long long超长整形详解 C 11 标准中,基于整数大小的考虑,共提供了如表 1 所示的这些数据类型。与此同时,标准中还明确限定了各个数据类型最少占用的位数。 表 1 C11标准中所有的整形数据类型 整数类型等价类型C11标准规定占用最少位数…...