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

STL源码剖析笔记——适配器(adapters)

系列文章目录

STL源码剖析笔记——迭代器
STL源码剖析笔记——vector
STL源码剖析笔记——list
STL源码剖析笔记——deque、stack,queue
STL源码剖析笔记——Binary Heap、priority_queue
STL源码剖析笔记——AVL-tree、RB-tree、set、map、mutiset、mutimap
STL源码剖析笔记——哈希表、unordered_set、unordered_map、unordered_mutiset、unordered_mutimap
STL源码剖析笔记——仿函数(函数对象)
STL源码剖析笔记——适配器(adapters)

文章目录

  • 系列文章目录
    • 1. 定义
    • 2. 容器适配器
    • 3. 迭代器适配器
    • 4. 仿函数适配器
      • (1)not1、not2
      • (2)bind1st、bind2nd
      • (3)compose1、compose2
      • (4)ptr_fun


1. 定义

  适配器(Adapter)是指一些特定的容器或迭代器,它们提供了不同于其底层实现的接口,以便与算法或其他容器进行协同工作,是通过将底层实现进行改造,以满足特定的需求。适配器跟底层实现的关系是包含而不是继承。 主要分为三种:容器适配器,迭代器适配器,仿函数适配器。

2. 容器适配器

  STL提供的两个容器queue和stack,其实都只不过是一种配接器。它们通过修饰底层的deque接口实现特殊的功能。从queue和stack的构造来看,两者内部都包含了一个queue,封住了所有的deque对外接口,只开放符合queue和stack原则的几个函数。queue和stack是容器,本质上也是作用于容器之上的一个适配器。

template <class T, class Sequence=deque<T> > 
class stack {
protected:Sequence c; //底层容器
};template <class T, class Sequence = deque<T> >
class queue {
protected:Sequence c; //底层容器
};

3. 迭代器适配器

  STL提供了许多应用于迭代器身上的配接器,包括insert Iterators, reverse iterators, iostream iteratorsors。他们本身就是迭代器,也是作用于迭代器上的一个适配器。通过修饰底层的迭代器接口实现特殊的功能,以reverse iterators为例:
reverse iterators的主要作用是实现反向迭代器遍历,rbegin()和rend()函数都是通过它来实现。
在这里插入图片描述
  对于一般的迭代器来说,begin()指向的是第一个元素,end()指向的是最后一个元素的后一个位置,是[ begin(), end() ),前闭后开。现在反向迭代器应该要保持这种设定,即rbegin()指向的是最后一个元素,rend()指向的是第一个元素的前一个位置。而且这种功能就要通过reverse iterators适配器来实现。
在这里插入图片描述
  可以看到reverse iterators中包含了一个正向的迭代器,对这个反向迭代器进行取值的操作,其实就是对内部的正向迭代器的前一位进行取值;包括其他的operator++,operator–,operator+,operator-,其实都是根据要求对内部包含的正向迭代器进行操作。

4. 仿函数适配器

  仿函数适配器functor adapters (亦称为function adapters)是所有配接器中数量最庞大的一个族群,其配接灵活度也是前二者所不能及,可以配接、配接、再配接。这些配接操作包括系结(bind)、否定(negate),组合(compose)、以及对一般函数或成员函数的修饰(使其成为一个仿函数)。下图为count_if()和 bind2nd (less () , 12))的搭配实例。
在这里插入图片描述
这个搭配想要得到数组中所有小于12的数,具体流程为:

  1.从count_if函数中可以知道,它接受两个迭代器(begin()和end())以及一个函数对象,将每一个迭代器取值放入函数对象中进行处理;

  2.less()是一个仿函数,接受两个参数,判断参数1是否小于参数2。

template <class T>
struct less:public binar_function<T, T, bool> {bool operator()(const T& x, const T& y) const { return x < y;}
};

  3.bind2nd内部有一个binder2nd对象,binder2nd接受一个模板对象和这个模板对象的第二参数类型,其operator()为将输入的value绑定到模板对象的第二参数。最后将bind2nd对象传给count_if作为pred的参数,实现功能。

(1)not1、not2

  not1、not2的功能为接收一个仿函数对象作为参数,并对返回值进行逻辑否定,区别在于not1用于接受一元函数,not2用于接受二元函数。

//辅助函数,使我们得以方便使用 unary_negate<Pred>
template <class Predicateinline unary_negate<Predicate> notl(const Predicated pred) { return unary_negate<Piedicate>(pred);
}//以下配接器用来表示某个Adaptable Predicate的逻辑负值 (logical negation) 
template <class Predicateclass unary_negate:public unary_function<typename Predicate::arguement_typex bool> { 
protected:Predicate pred; / / 内部成员
public:explicit unary_negate(const Predicated x):pred(x) {}bool operator()(const typename Predicate::argument_type& x) const { return !pred(x); / / 将pred的运算结果加上否定(negate)运算}
};//辅助函数,使我们得以方便使用bineary_negate<Pred>
template<class Predicate>
inline binary_negate<Predicate> not2(const Predicated pred) { return binary_negate<Predicate>(pred);
}//以下配接器用来表示某个Adaptable Binary Predicate的逻辑负值 template <class Predicate>
class binary_negate:public binary_function<typename Predicate::first_argument_type, typename Predicate::second_argument_type, bool> {
protected:Predicate pred; // 内部成员
public:explicit binary_negate(const Predicated x) : pred(x) {}bool operator()(const typename Predicate::first_argument_type& const typename Predicate::second_arguinent_type& y) const {return !pred(x, y); //将pred的运算结果加上否定(negate)运算}
};

(2)bind1st、bind2nd

//辅助函数,让我们得以方便使用binderlst<Op> template <class Operation, class T>
inline binder1st<Operation> bind1st(const Operation& op, const T& x) {typedef typename Operation::first_argument_type argl_type;return binderlst<Operation>(op, argl_type(x));//以上,注意,先把x转型为op的第一参数型别
}template <class Operation>
class binder1st:public unary_function<typename Operation::second_argument_type, typename Operation::result_type> { 
protected:Operation op; // 内部成员typename Operation::first_argument_type value;// 内部成员
public:
// constructorbinder1st(const Operation& x, const typename Operation::first_argument_type& y):op (x),value (y) {} //将表达式和第一参数记录于内部成员typename Operation::result_typeoperator()(const typename Operation::second_argtunent_type& x) const {return op (value, x); //实际调用表达式,并将value绑定为第一参数
} );

  bind1st的功能是将一个二元函数转变为一元函数,他接受一个函数对象和一个函数对象第一参数类型的值,并将这个值绑定到函数对象的第一参数,返回这个函数对象的返回类型。

    std::less<int> lessThan;std::binder1st<std::less<int>> lessThan5 = std::bind1st(lessThan, 5);bool result = lessThan5(3);  // 相当于lessThan(5, 3)

  bind2nd与bind1st唯一区别在于,bind2nd将值绑定到对象的第二参数。

(3)compose1、compose2

已知两个一元函数f () , g (),配接器compose1用来产生一个h(), 使得h(x)= f(g(x)),即:

               conpose1( f () , g () )的效果等于f( g(x) )

//辅助函数,让我们得以方便运用 unary_compose<Opl,0p2>
template <class Operationl, class Operation2>
inline unary_compose<Operationl, Operation2> composel(const Operationl& opl, const Operation2& op2) {return unary_compose<Operationl, Operation2>(opl, op2);
}template <class Operationl, class Operation2>
class unary_compose:public unary_function<typename Operatioh2::argument^type, typename Operatiohl::result_type> { 
protected:Operationl op1; //内部成员Operation2 op2;// 内吾B成员
public:
// constructor
unary_compose(const Operationl& x, const 0peration2& y):opl (x) , op2 (y) {} / /将两个表达式记录于内部成员typename Operationl::result_typeoperator()(const typename Operations::ar0mnent_type& x) const {return opl (op2 (x) );// 函数合成
};

相应的,已知两个一元函数f () , g ()和一个二元函数h(),配接器compose2用来产生一个F(), 使得F(x)= H( f () , g () ),即:
               conpose2( H(), f () , g () )的效果等于H( f () , g () )

(4)ptr_fun

//辅助函数,让我们得以方便运用pointer_to_unary_function
template <class Arg, class Result>
inline pointer_to_unary_function<Arg, Result> ptr_fun(Result (*x)(Arg)) {return pointer_to_unary_function<Arg,Result>(x);
}//以下配接器其实就是把一个一元函数指针包起来:
//当仿函数被使用时,就调用该函数指针
template <class Arg, class Result>
class pointer_to_unary_function:public unary_functioi<Arg, Result> {
protected:Result (*ptr) (Arg);//内部成员,一个函数指针
public:pointer_to_unary_function() {}
//以下constructor将函数指针记录于内部成员之中explicit pointer_to_unary_function(Result (*x)(Arg)) : ptr(x) {}
//以下,通过函数指针执行函数Result operator()(Arg x) const { return ptr(x);} 
};

ptr_fun配接器其实就是把一个一元函数指针包起来,当仿函数被使用时,就调用该函数指针。

相关文章:

STL源码剖析笔记——适配器(adapters)

系列文章目录 STL源码剖析笔记——迭代器 STL源码剖析笔记——vector STL源码剖析笔记——list STL源码剖析笔记——deque、stack&#xff0c;queue STL源码剖析笔记——Binary Heap、priority_queue STL源码剖析笔记——AVL-tree、RB-tree、set、map、mutiset、mutimap STL源…...

Mysql、Oracle区分大小写?

Mysql Windows 系统的文件名不区分大小写&#xff0c;所以运行在 Windows 系统上面的 MySQL 服务器也不用区分数据库名和表名的大小写。Linux 系统大小写规则&#xff1a; 数据库名与表名严格区分大小写表的别名严格区分大小写变量名严格区分大小写列名与列的别名忽略大小写 M…...

Java多线程并发(二)

四种线程池 Java 里面线程池的顶级接口是 Executor&#xff0c;但是严格意义上讲 Executor 并不是一个线程池&#xff0c;而只是一个执行线程的工具。真正的线程池接口是 ExecutorService。 newCachedThreadPool 创建一个可根据需要创建新线程的线程池&#xff0c;但是在以前…...

树莓派外接上显示器以后一直黑屏无画面显示

一般遇到这种情况都是因为没有强制支持热插拔引起的&#xff0c;先断电树莓派&#xff0c;确保显示器与树莓派连接正常&#xff0c;然后上电就可以正常显示了。 如果想要支持热插拔&#xff0c;可以修改配置文件。 sudo nano /boot/config.txt 修改如下配置 hdmi_force_hotpl…...

使用Ansible lineinfile模块进行行级别操作

Ansible是一种功能强大的自动化工具&#xff0c;它提供了各种模块来简化配置管理任务。其中&#xff0c;lineinfile模块是一种特别有用的模块&#xff0c;它允许我们在文件中插入、修改或删除行。本文将介绍Ansible的lineinfile模块&#xff0c;并演示如何使用它来进行行级别操…...

curl 18 HTTP/2 stream

cd /Users/haijunyan/Desktop/CustomKit/KeepThreadAlive/KeepThreadAlive //Podfile所在文件夹 git config --global https.postBuffer 10485760000 git config --global http.postBuffer 10485760000 pod install https://blog.csdn.net/weixin_41872403/article/details/86…...

5G+AI开花结果,助力智慧安检落地

“请带包的乘客过机安检&#xff01;”&#xff0c;深圳地铁、腾讯共同打造的5GAI智慧安检辅助系统亮相福田枢纽站&#xff0c;进一步解放了人力&#xff0c;提高安检效率&#xff0c;为交通安全保驾护航&#xff0c;让智慧出行成为现实。 传统的安检设备均为人工肉眼辨识&…...

Swift 如何实现自定义 Tab Bar

前言 每个 UI 设计师都喜欢美丽而有动画效果的 Tab Bar。然而&#xff0c;对于开发人员来说&#xff0c;实现这种设计可能是一场噩梦。当然&#xff0c;使用 Apple 的原生 Tab Bar 组件并专注于更有趣的事情&#xff0c;比如业务逻辑的实现&#xff0c;会更容易。但如果我们必…...

mysql 语言学习

整理了一下 mysql 操作语言&#xff0c;不是很全&#xff0c;部分地方也许需要修改&#xff0c;先放上来&#xff0c;有时间再慢慢完善。 一、数据库操作 连接数据库 $ sudo mysql [-h ip] -u root -p [-P 3306] 初始化数据库 $ mysql_secure_installation备份数据库 # 备…...

微信小程序基础bug

1.苹果11手机小程序请求数据不显示 设置-》隐私-》分析与改进-》开启 ”与开发者共享“ 2.<navigator>组件回退delta不成功 tabBar 页面是不能实现后退的效果的. 因为, 当我们跳转到 tabBar 页面&#xff0c;会关闭其他所有非tabBar 页面,所以当处于 tabBar 页面时, 无…...

13、pytest为失败的断言定义自己的解释

官方实例 # content of ocnftest.py from test_foocompare import Foodef pytest_assertrepr_compare(op, left, right):if isinstance(left, Foo) and isinstance(right, Foo) and op "":return["Comparing Foo instances:",f" vals:{left.val} !…...

Flink优化——数据倾斜(二)

目录 数据倾斜 判断是否存在数据倾斜 数据倾斜的解决 KeyBy之前发生数据倾斜 KeyBy之后发生的数据倾斜 聚合操作存在数据倾斜 窗口聚合操作存在数据倾斜 数据倾斜 判断是否存在数据倾斜 相同 Task 的多个 Subtask 中&#xff0c;个别 Subtask 接收到的数据量明显大于其…...

Unity打包到Webgl平台以及遇到的问题

Unity打包到Webgl平台以及遇到的问题 参考网站 Unity打包WebGL的全过程及在打包和使用过程中会遇到的问题(本地测试)-CSDN博客 unity打包到Webgl 并配置能正常运行 这里我用的是Unity2022.3.3f1c1版本 有两种方法 1、配置本地web服务 2、安装vsCode>添加插件LiveServe…...

c语言编程题经典100例——(90~95例)

1,写一个函数&#xff0c;实现数字的加密和解密。 下面是一个简单的C语言函数&#xff0c;可以实现数字的加密和解密。这个函数采用简单的加密算法&#xff0c;将输入的数字乘以一个固定的密钥&#xff0c;然后加上一个固定的偏移量。解密过程就是将加密后的数字减去偏移量&am…...

Redis核心知识点总结

1.Redis介绍 Redis 是 NoSQL&#xff0c;但是可处理 1 秒 10w 的并发&#xff08;数据都在内存中&#xff09; 使用 java 对 redis 进行操作类似 jdbc 接口标准对 mysql&#xff0c;有各类实现他的实现类&#xff0c;我们常用的是 druid 其中对 redis&#xff0c;我们通常用 J…...

stm32Flash操作

//G0B0 flash大小 0x08000000-0x0807FFFF 512K(0400 1K)//2k 1页 //初始化标记数据地址 放最前面 脱机烧写器可擦除掉 #define CONST_INITMARKDATA_ADDRESS (0x0807D000UL) //2k 1页 //射频数据地址 #define CONST_FREQDATA_ADDRESS (0x0807F000UL) //2…...

云原生系列1

1、虚拟机集群环境准备 VirtualBox类似vmware的虚拟化软件&#xff0c;去官网https://www.virtualbox.org/下载最新版本免费的&#xff0c;VirtualBox中鼠标右ctrl加home跳出鼠标到wins中。 VirtualBox安装步骤 https://blog.csdn.net/rfc2544/article/details/131338906 cent…...

设计原则 | 里式替换原则

一、里式替换原则&#xff08;Liskov Substitution Principle &#xff09; 1、原理 子类型必须能替换掉它们的基类型&#xff0c;在使用继承时&#xff0c;遵循里式替换原则&#xff0c;在子类中尽量不要重写父类中的方法。里式替换原则告诉我们&#xff0c;继承实际上让两个…...

第7节:Vue3 动态绑定多个属性

可以使用v-bind指令将多个属性动态绑定到元素上。以下是一个简单的实例&#xff1a; <template><view class"container"><text v-bind"dynamicProps">{{ message }}</text><button click"toggleActive">切换激活…...

【文件上传系列】No.1 大文件分片、进度图展示(原生前端 + Node 后端 Koa)

分片&#xff08;500MB&#xff09;进度效果展示 效果展示&#xff0c;一个分片是 500MB 的 分片&#xff08;10MB&#xff09;进度效果展示 大文件分片上传效果展示 前端 思路 前端的思路&#xff1a;将大文件切分成多个小文件&#xff0c;然后并发给后端。 页面构建 先在页…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)

引言 工欲善其事&#xff0c;必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后&#xff0c;我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集&#xff0c;就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...