当前位置: 首页 > news >正文

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_iteratorback_insert_iteratorinsert_iterator
  • 反向迭代器:reverse_iterator
  • 流迭代器:ostream_iteratoristream_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适配器就是接口&#xff0c;对容器、迭代器、算法进行包装&#xff0c;但其实质还是…...

防抖和节流

防抖和节流的区别&#xff1f;防抖&#xff1a;触发高频事件后n 秒内 函数只会执行一次&#xff0c;如果n秒内 高频事件在在次触发&#xff0c;则会重新计算节流&#xff1a;高频事件触发&#xff0c;但在n 秒内 只会执行一次&#xff0c;所以节流会稀释函数的执行频率下面就是…...

vue3 微信扫码登录及获取个人信息实现的三种方法

一、流程&#xff1a; 微信提供的扫码方式有两种,分别是: 跳转二维码扫描页面 内嵌式二维码根据文档我们可以知道关于扫码授权的模式整体流程为: 1. 第三方发起微信授权登录请求&#xff0c;微信用户允许授权第三方应用后&#xff0c;微信会拉起应用或重定向到第三方网站&…...

Java8 新特性强大的Stream API

一、Stream API 说明 Java8中有两大最为重要的改变。第一个是 Lambda 表达式&#xff1b;另外一个则是 Stream API。 Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充&#xff0c;因为Stream API可以极大提供Ja…...

day22_IO

今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、作业 二、缓冲流 三、字符流 四、缓冲字符流 五、匿名内部类 零、 复习昨日 File: 通过路径代表一个文件或目录 方法: 创建型,查找类,判断类,其他 IO …...

第三十八章 linux-并发解决方法二(信号量)

第三十八章 linux-并发解决方法二&#xff08;信号量&#xff09; 文章目录第三十八章 linux-并发解决方法二&#xff08;信号量&#xff09;信号量的定义DOWN操作UP操作相对于自旋锁&#xff0c;信号量的最大特点是允许调用它的线程进入睡眠状态这意味着试图获得某一信号的进程…...

数据结构-考研难点代码突破(C++实现树型查找 - B树插入与遍历,B+树基本概念)

数据结构&#xff08;C&#xff09;[B树&#xff08;B-树&#xff09;插入与中序遍历&#xff0c;效率分析]、B树、B*树、B树系列应用 文章目录1. B树B树的插入与删除流程2. B树&#xff08;MySQL&#xff09;3. B树与B树对比4. C实现B树插入&#xff0c;中序遍历1. B树 B树类…...

Python可视化界面编程入门

Python可视化界面编程入门具体实现代码如所示&#xff1a; &#xff08;1&#xff09;普通可视化界面编程代码入门&#xff1a; import sys from PyQt5.QtWidgets import QWidget,QApplication #导入两个类来进行程序界面编程if __name__"__main__":#创建一个Appl…...

基于Java+SpringBoot+Vue前后端分离书店购书系统设计与实现

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战✌ 博主作品&#xff1a;《微服务实战》专栏是本人的实战经验总结&#xff0c;《Spring家族及…...

Android:截屏/视频截图

需求描述 实现截取Android应用当前界面的功能&#xff0c;需包含界面中视频&#xff08;此博客的参考代码以存储在设备本地的视频为例&#xff0c;未检验在线视频的情况&#xff09;当前的播放帧截图。 调研准备 首先应用需要获取设备存储的读写权限&#xff0c;需要在Andro…...

leecode-C语言实现-28. 找出字符串中第一个匹配项的下标

一、题目给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。示例 1&#xff1a;输入&#xff1a;haystack …...

使用 Postman 实现 API 自动化测试

目录&#xff1a;导读 背景介绍 名词解析 使用说明 执行 API 测试 集成 CI 实现 API 自动化测试 写在最后 背景介绍 相信大部分开发人员和测试人员对 postman 都十分熟悉&#xff0c;对于开发人员和测试人员而言&#xff0c;使用 postman 来编写和保存测试用例会是一种比…...

k8s环境jenkins发布vue项目指定nodejs版本

k8s环境jenkins发布vue项目指定nodejs版本1、背景2、分析3、解决方法3.1、 找到配置镜像位置3.2、 制作新镜像3.3、 推送镜像到私有仓库3.4、 修改配置文件1、背景 发布一个前端项目&#xff0c;它需要nodejs 16.9.0版本支持&#xff0c;而kubesphere 3.2.0集成的jenkins 的镜…...

我应该把毕业设计做到什么程度才能过关?

本篇博客包含了狗哥多年职业生涯对于软件项目的一丢丢理解&#xff0c;也讲述了对于大学生毕业设计的一些理解。如果你还是懵懵懂懂就要离开学校了&#xff0c;被老师告知不得不做出一套毕业设计的时候&#xff0c;希望你可以看到这篇博客&#xff0c;让你有点头绪&#xff0c;…...

力扣-合作过至少三次的演员和导演

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;1050. 合作过至少三次的演员和导演二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运…...

【 PMU】信号生成、采样、分割、估计器应用和误差计算(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…...

电子技术——AB类输出阶的偏置

电子技术——AB类输出阶的偏置 下面我们介绍两种AB类输出阶的偏置的方法。 使用二极管偏置 下图展示了电流源 III 加两个二极管的偏置方法&#xff1a; 因为输出阶需要大功率输出&#xff0c;因此输出推挽三极管可能是几何体积比较大的晶体管。对于二极管来说&#xff0c;并不…...

元宇宙营业厅,数字技术融合,赋能实体经济

在我国数字经济与虚拟服务市场规模扩大下&#xff0c;元宇宙营业厅强势来袭&#xff0c;从多场景、多内容&#xff0c;深耕高效协同的特色功能&#xff0c;基于多元化、灵活的交互体验&#xff0c;更大程度上解决线上业务办理抽象繁琐&#xff0c;线下业务办理的时空受限、业务…...

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…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...