C++ STL 适配器

系列文章目录

模板特例化,偏特化,左右值引用 https://blog.csdn.net/surfaceyan/article/details/126794013
C++ STL 关联容器 https://blog.csdn.net/surfaceyan/article/details/127414434
C++ STL 序列式容器(二) https://blog.csdn.net/surfaceyan/article/details/127083966
C++ STL 序列式容器(一) https://blog.csdn.net/surfaceyan/article/details/126860166
C++STL迭代器iterator设计 https://blog.csdn.net/surfaceyan/article/details/126772555
C++11 标准库头文件模拟实现,无锁STL https://blog.csdn.net/surfaceyan/article/details/126772555


文章目录

  • 系列文章目录
  • 前言
  • 概念分类
    • 容器适配器
    • 迭代器适配器
      • 1. insert iterators
      • 2. reverse iterators
      • 3. stream iterators
  • function adapters
    • 4. 用于函数指针:ptr_fun
    • 5. 用于成员函数指针: mem_fun, mem_fun_ref
  • 总结


前言

适配器(adapters)在STL组件的灵活组合运用上扮演者重要角色。Adapter这个概念源于23个设计模式中的一个:将一个class的接口转换为以一个class接口,使原本因接口不兼容而不能合作的classes可以一起运作。

实际上就是在原有的接口上再套一层接口
或许叫接口适配器或者接口层也可


概念分类

改变函数对象接口的称为function adapter,改变容器接口的称为 container adapter, 改变迭代器接口的称为 iterator adapter。

queue和stack就是容器适配器。

容器适配器和迭代器适配器

#include <iterator>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
    ostream_iterator<int> outite(cout, " ");
    int ia[] = {0,1,2,3,4,5};
    deque<int> id(ia, ia+6);
    copy(id.begin(), id.end(), outite);
    cout << endl;
    
    copy(ia+1, ia+2, front_inserter(id));
    copy(ia+3, ia+4, back_inserter(id));
    copy(id.begin(), id.end(), outite);
    cout << endl;

    deque<int>::iterator ite = find(id.begin(), id.end(), 5);
    copy(ia+0, ia+3, inserter(id, ite));
    copy(id.begin(), id.end(), outite);
    cout << endl;

    copy(id.rbegin(), id.rend(), outite);
    cout << endl;

    istream_iterator<int> inite(cin), eos;  // end-of-stream
    copy(inite, eos, inserter(id, id.begin()));

    copy(id.begin(), id.end(), outite);
    cout << endl;
}

应用于函数的适配器
所有期望获取适配能力的组件,本事必须是可适配的,也就是说,一元仿函数必须继承自 unary_function,二元仿函数必须继承自 binary_function ,成员函数必须以mem_fun处理过,一般函数必须以 ptr_fun 处理过,一个未经ptr_fun处理的一般函数,虽然也可以函数指针的形式传递STL算法使用,却无法有任何适配能力

void print(int i)
{
    cout << i << ' ';
}
class Int
{
private:
    int m_i;
public:
    explicit Int(int i) : m_i(i) {}
    ~Int() {}
    void print1() const 
    {
        cout << '[' << m_i << ']';
    }
};

template<class Arg, class Result>
struct unary_function 
{
  typedef Arg     argument_type;
  typedef Result    result_type;
};

template <class Arg1, class Arg2, class Result>
struct binary_function
{
  typedef Arg1   first_argument_type;
  typedef Arg2  second_argument_type;
  typedef Result         result_type;
};

    stringstream scout;
    ostream_iterator<int> outite(scout, " ");
    int ia[6] = {2, 21, 12, 7, 19, 23};
    vector<int> iv(ia, ia+6);
    cout << count_if(iv.begin(), iv.end(), [](int a)->bool {return a>=12;});
    cout << endl;

    transform(iv.begin(), iv.end(), outite, [](int a)->int {return (a+2)*3;});
    cout << scout.str() << endl;

    copy(iv.begin(), iv.end(), outite);
    cout << scout.str() << endl;

    for_each(iv.begin(), iv.end(), print);
    cout << endl;

    for_each(iv.begin(), iv.end(), ptr_fun(print));
    cout << endl;

    for_each(iv.begin(), iv.end(), bind(print, placeholders::_1));
    cout << endl; 

    Int t1(3), t2(7), t3(20), t4(14), t5(68);
    vector<Int> Iv;
    Iv.push_back(t1);
    Iv.push_back(t2);
    Iv.push_back(t3);
    Iv.push_back(t4);
    Iv.push_back(t5);
    for_each(Iv.begin(), Iv.end(), mem_fun_ref(&Int::print1));  // 私有成员函数必须用指针
    cout << endl;

    for_each(Iv.begin(), Iv.end(), bind(&Int::print1, placeholders::_1));
    cout << endl;

其中std::bind是更易于使用更通用的方法,用它!

容器适配器

template<typename T, typename Sequence = deque<T>>
class stack{
protected:
  Sequence c;
  ...
};

迭代器适配器

由用户指定一个容器,在调用 迭代器适配器 时调用指定容器的对应方法

1. insert iterators

可细分为back insert iterator, front insert iterator和insert iterator,分别将对应类型的“指针解引用并赋值”(*p = value)操作修改为对应容器的方法

template<class Container>
class back_insert_iterator
{
protected:
    Container* container;
public:
    typedef std::output_iterator_tag iterator_category;
    typedef void                       value_type;
    typedef void                  difference_type;
    typedef void                          pointer;
    typedef void                        reference;

    explicit back_insert_iterator(Container& x) : container(&x) {};
    back_insert_iterator& operator=(const typename Container::value_type& value)
    {
        container->push_back(value);
        return *this;
    }
    back_insert_iterator& operator*() {return *this;}
    back_insert_iterator& operator++() {return *this;}
    back_insert_iterator& operator++(int) {return *this;}
};
template <class Container>
class front_insert_iterator
{
protected:
    Container* container;
public:
    typedef std::output_iterator_tag iterator_category;
    typedef void                       value_type;
    typedef void                  difference_type;
    typedef void                          pointer;
    typedef void                        reference;

    explicit front_insert_iterator(Container& c) : container(&c) {}
    front_insert_iterator& operator=(const typename Container::value_type& v)
    {
        container->push_front(v);
        return *this;
    }
    front_insert_iterator& operator*() {return *this;}
    front_insert_iterator& operator++() {return *this;}
    front_insert_iterator& operator++(int) {return *this;}
};
template <class Container>
class insert_iterator
{
protected:
    Container* container;
    typename Container::iterator iter;
public:
    typedef std::output_iterator_tag iterator_category;
    typedef void                       value_type;
    typedef void                  difference_type;
    typedef void                          pointer;
    typedef void                        reference;

    explicit insert_iterator(Container& c, typename Container::iterator i) : container(&c), iter(i) {}
    insert_iterator& operator=(const typename Container::value_type& v)
    {
        iter = container->insert(iter, v);
        ++iter;
        return *this;
    }
    insert_iterator& operator*() {return *this;}
    insert_iterator& operator++() {return *this;}
    insert_iterator& operator++(int) {return *this;}
};


template <class Container>
inline back_insert_iterator<Container> back_inserter(Container& x)
{
    return back_insert_iterator<Container>(x);
}
template <class Container>
inline front_insert_iterator<Container> front_inserter(Container& x)
{
    return front_insert_iterator<Container>(x);
}
template <class Container, class Iterator>
inline insert_iterator<Container> inserter(Container& x, Iterator i)
{
    typedef typename Container::iterator iter;
    return insert_iterator<Container>(x, iter(i));
}

int main()
{
    std::deque<int> v{1,2,3};
    auto bins = ::front_inserter(v);

    *bins = 4;
    *bins = 6;

    std::ostream_iterator<int> outite(std::cout, " ");
    std::copy(v.begin(), v.end(), outite); std::cout << std::endl;
}

2. reverse iterators

和reverse_iterator迭代器相关,将移动操作倒转
copy(v.rbegin(), v.rend(), ite)看似简单,实则暗藏玄机

typedef reverse_iterator<iterator> reverse_iterator;
reverse_iterator rbegin() {return reverse_iterator(end());}
reverse_iterator rend() {return reverse_iterator(begin());}

在这里插入图片描述


template <class Iterator>
class reverse_iterator
{
protected:
    Iterator current;  // 记录对应之正向迭代器
public:
    typedef typename std::iterator_traits<Iterator>::iterator_category  iterator_category;
    typedef typename std::iterator_traits<Iterator>::value_type                value_type;
    typedef typename std::iterator_traits<Iterator>::difference_type      difference_type;
    typedef typename std::iterator_traits<Iterator>::pointer                      pointer;
    typedef typename std::iterator_traits<Iterator>::reference                  reference;
    typedef Iterator          iterator_type;
    typedef reverse_iterator<Iterator> self;

    reverse_iterator() {}
    explicit reverse_iterator(iterator_type x) : current(x) {}
    reverse_iterator(const self& x): current(x.current) {}
    iterator_type base() const {return current;}
    reference operator*() const
    {
        Iterator tmp = current;
        return *--tmp;  // key point
    }
    pointer operator->() const 
    {
        return &(operator*());
    }
    self& operator++()
    {
        --current;
        return *this;
    }
    self operator++(int)
    {
        self tmp = *this;
        --current;
        return tmp;
    }
    self& operator--()
    {
        ++current;
        return *this;
    }
    self operator--(int)
    {
        self tmp = *this;
        ++current;
        return tmp;
    }
    self operator+(difference_type n) const
    {
        return self(current - n);
    }
    self& operator+=(difference_type n)
    {
        current -= n;
        return *this;
    }
    self operator-(difference_type n) const
    {
        return self(current + n);
    }
    self& operator-=(difference_type n)
    {
        current += n;
        return *this;
    }
    difference_type operator-(const self& second) const
    {
        return second.current - current;
    }
    reference operator[](difference_type n) const 
    {
        return *(*this+n);
    }
};


int main()
{
    std::deque<int> v{1,2,3};
    ::reverse_iterator<std::deque<int>::iterator> rbegin(v.end()), rend(v.begin());


    std::ostream_iterator<int> outite(std::cout, " ");
    // copy到outite迭代器所指的位置
    std::copy(rbegin, rend, outite); std::cout << std::endl;
}

3. stream iterators

就是将迭代器绑定到一个stream对象身上。绑定到istream(std::cin)身上叫istream_iterator,拥有输入能力;绑定到ostream(std::cout)身上的叫ostream_iterator, 拥有输出能力。
所谓绑定是指,在iterator内部维护一个stream成员,客户端对该iterator的所有操作都转换成该stream成员的操作。

template <typename T, typename Distance = std::ptrdiff_t>
class istream_iterator
{
friend bool operator==(const istream_iterator<T, Distance>& x, const istream_iterator<T, Distance>& y);

protected:
    std::istream* stream;
    T value;
    bool end_marker;
    void read()
    {
        end_marker = (*stream) ? true : false;
        if (end_marker) *stream >> value;
        end_marker = (*stream) ? true : false;
    }
public:
    typedef std::input_iterator_tag  iterator_category;
    typedef T                               value_type;
    typedef Distance                   difference_type;
    typedef const T*                           pointer;
    typedef const T&                         reference;

    istream_iterator() : stream(&std::cin), end_marker(false) {}
    explicit istream_iterator(std::istream& s) : stream(&s) { read(); }
    reference operator*() const { return value; }
    pointer operator->() const { return &(operator*()); }
    istream_iterator& operator++()
    {
        read();
        return *this;
    }
    istream_iterator operator++(int)
    {
        istream_iterator<T, Distance> tmp = *this;
        read();
        return tmp;
    }
}; 
template <typename T>
class ostream_iterator
{
protected:
    std::ostream* stream;
    const char* string;
public:
    typedef std::output_iterator_tag  iterator_category;
    typedef void                             value_type;
    typedef void                        difference_type;
    typedef void                                pointer;
    typedef void                              reference;

    explicit ostream_iterator(std::ostream& s) : stream(&s), string(0) {}
    ostream_iterator(std::ostream& s, const char* c) : stream(&s), string(c) {}
    ostream_iterator operator=(const T& value)
    {
        *stream << value;
        if (string) *stream << string;
        return *this;
    }
    ostream_iterator& operator*() {return *this;}
    ostream_iterator& operator++() {return *this;}
    ostream_iterator& operator++(int) {return *this;}
}; 

以上两个迭代器在应用上非常重要,说明了如何为自己量身定制一个迭代器。可以完成一个绑定到 Internet Explorer 身上的迭代器,也可以完成一个绑定到磁盘目录上的迭代器······

function adapters

std::bind

4. 用于函数指针:ptr_fun

@deprecated Deprecated in C++11, no longer in the standard since C++17.

5. 用于成员函数指针: mem_fun, mem_fun_ref

在这里插入图片描述
@deprecated Deprecated in C++11, no longer in the standard since C++17. Use mem_fn instead.

std::mem_fn


总结

algorithm里存放各种算法如accumulate,sort等
functional里存各种xx函数如std::move, less, greater等

适配器一般要和泛型算法配合使用方可体现其强大之处

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

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

相关文章

基于准静态自适应环型缓存器(QSARC)的taskBus万兆吞吐实现

文章目录 概要整体架构流程技术名词解释技术细节1. 数据结构2. 自适应计算队列大小3. 生产者拼接缓存4. 高效地通知消费者 小结1. 性能表现情况2. 主要改进3. 源码和发行版 概要 准静态自适应环形缓存器&#xff08;Quasi-Static Adaptive Ring Cache&#xff09;是taskBus用于…

STM32F407VET6开发板RT-Thread MSH 串口的适配

相关文章 STM32F407VET6开发板RT-Thread的移植适配 环境 STM32F407VET6 开发板&#xff08;魔女&#xff09;&#xff0c;http://www.stm32er.com/ Keil MDK5&#xff0c;版本 5.36 串口驱动 RT-Thread 通过适配 串口驱动&#xff0c;可以使用 MSH shell 当前手动搭建的 …

详细分析linux中的MySql跳过密码验证以及Bug(图文)

目录 1.问题所示2. 基本知识3. 解决方法3.1 跳过验证Bug3.2 设定初始密码 1.问题所示 发现密码验证错误&#xff0c;遗失密码 2. 基本知识 停止MySQL服务&#xff1a;sudo systemctl stop mysql 以跳过权限表模式启动MySQL&#xff1a;sudo mysqld_safe --skip-grant-tables …

论文解读 | ACL2024 Outstanding Paper:因果指导的主动学习方法:助力大语言模型自动识别并去除偏见...

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 点击阅读原文观看作者直播讲解回放&#xff01; 作者简介 孙洲浩&#xff0c;哈尔滨工业大学SCIR实验室博士生 概述 尽管大语言模型&#xff08;LLMs&#xff09;展现出了非常强大的能力&#xff0c;但它们仍然…

MATLAB-基于高斯过程回归GPR的数据回归预测

目录 目录 1 介绍 1. 1 高斯过程的基本概念 1.2 核函数&#xff08;协方差函数&#xff09; 1.3 GPR 的优点 1.4. GPR 的局限 2 运行结果 3 核心代码 1 介绍 高斯过程回归&#xff08;Gaussian Process Regression, GPR&#xff09;是一种强大的非参数贝叶斯方法&…

如何用GPU算力卡P100玩黑神话悟空?

精力有限&#xff0c;只记录关键信息&#xff0c;希望未来能够有助于其他人。 文章目录 综述背景评估游戏性能需求显卡需求CPU和内存系统需求主机需求显式需求 实操硬件安装安装操作系统Win11安装驱动修改注册表选择程序使用什么GPU 安装黑神话悟空其他 综述 用P100 PCIe Ge…

一台手机一个ip地址吗?手机ip地址泄露了怎么办

在数字化时代&#xff0c;‌手机作为我们日常生活中不可或缺的一部分&#xff0c;‌其网络安全性也日益受到关注。‌其中一个常见的疑问便是&#xff1a;‌“一台手机是否对应一个固定的IP地址&#xff1f;‌”实际上&#xff0c;‌情况并非如此简单。‌本文首先解答这一问题&a…

Linux_kernel移植rootfs10

一、动态更改内核 1、low level&#xff08;静态修改&#xff09; 【1】将led_drv.c拷贝到kernel/drivers/char/目录中 【2】修改当前目录下的Makefile文件 obj-y led_drv.o #将新添加的驱动文件加入到Makefile文件中 【3】退回kernel目录&#xff0c;执行make uImage …

C语言学习笔记 Day16(C10文件管理--下)

Day16 内容梳理&#xff1a; C语言学习笔记 Day14&#xff08;文件管理--上&#xff09;-CSDN博客 C语言学习笔记 Day15&#xff08;文件管理--中&#xff09;-CSDN博客 目录 Chapter 10 文件操作 10.5 文件状态 10.6 文件的随机读写 fseek()、rewind() &#xff08;1&…

【初阶数据结构】详解栈和队列(来自知识星空的一抹流光)

文章目录 前言1. 栈1.1 栈的概念及结构1.2 栈的实现1.2.1 "栈"实现的选择 1.3 栈的代码实现1.3.1 栈的结构体定义&#xff08;用的是顺序表&#xff09;1.3.2 栈的头文件设置1.3.3 栈的各功能的实现 2. 队列2.1 队列的概念及结构2.2 "队列"实现的选择2.3 队…

【即时通讯】轮询方式实现

技术栈 LayUI、jQuery实现前端效果。django4.2、django-ninja实现后端接口。 代码仓 - 后端 代码仓 - 前端 实现功能 首次访问页面并发送消息时需要设置昵称发送内容为空时要提示用户不能发送空消息前端定时获取消息&#xff0c;然后展示在页面上。 效果展示 首次发送需要…

深入理解数据库的 4NF:多值依赖与消除数据异常

在数据库设计中&#xff0c; "范式" 是一个常常被提到的重要概念。许多初学者在学习数据库设计时&#xff0c;经常听到第一范式&#xff08;1NF&#xff09;、第二范式&#xff08;2NF&#xff09;、第三范式&#xff08;3NF&#xff09;以及 BCNF&#xff08;Boyce-…

滑动窗口在算法中的应用

滑动窗口是一种经典的算法技巧&#xff0c;就像在处理一系列动态数据时&#xff0c;用一扇可以滑动的“窗口”来捕捉一段连续的子数组或子字符串。通过不断地移动窗口的起点或终点&#xff0c;我们能够以较低的时间复杂度来解决一系列问题。在这篇文章中&#xff0c;我们将通过…

维信小程序禁止截屏/录屏

一、维信小程序禁止截屏/录屏 //录屏截屏,禁用wx.setVisualEffectOnCapture({visualEffect:hidden});wx.setVisualEffectOnCapture(Object object) 测试安卓手机&#xff1a; 用户截屏&#xff0c;被禁用 用户录屏&#xff0c;录制的是空白内容/黑色内容的视频。 二、微信小…

C++ | Leetcode C++题解之第386题字典序排数

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> lexicalOrder(int n) {vector<int> ret(n);int number 1;for (int i 0; i < n; i) {ret[i] number;if (number * 10 < n) {number * 10;} else {while (number % 10 9 || numbe…

EasyPlayer.js网页H5 Web js播放器能力合集

最近遇到一个需求&#xff0c;要求做一款播放器&#xff0c;发现能力上跟EasyPlayer.js基本一致&#xff0c;满足要求&#xff1a; 需求 功性能 分类 需求描述 功能 预览 分屏模式 单分屏&#xff08;单屏/全屏&#xff09; 多分屏&#xff08;2*2&#xff09; 多分屏…

【阿一网络安全】如何让你的密码更安全?(二) - 非对称加密

上次《【阿一网络安全】如何让你的密码更安全&#xff1f;(一) - 对称加密》提到加密算法的对称加密&#xff0c;我们这次来聊聊非对称加密。 和对称加密不同&#xff0c;非对称加密的加密密钥和解密密钥不同。 非对称加密 大概过程就是&#xff0c;发送方使用公钥对明文数据…

mac 安装redis

官网下载指定版本的redis https://redis.io/ 目前3.2.0 是最新最稳定的 版本 这里是历史版本下载 下载指定版本 安装 1.放到自定义目录下并解压 2.打开终端&#xff0c;执行命令 cd redis的安装目录下 make test -- 此命令的作用是将redis源代码编译成可执行文件&#xff0c…

SPI驱动学习五(如何编写SPI设备驱动程序)

目录 一、SPI驱动程序框架二、怎么编写SPI设备驱动程序1. 编写设备树2. 注册spi_driver3. 怎么发起SPI传输3.1 接口函数3.2 函数解析 三、示例1&#xff1a;编写SPI_DAC模块驱动程序1. 要做什么事情2. 硬件2.1 原理图2.2 连接 3. 编写设备树4. 编写驱动程序5. 编写app层操作程序…

C++语法知识点合集:11.模板

文章目录 一、非类型模板参数1.非类型模板参数的基本形式2.指针作为非类型模板参数3.引用作为非类型模板参数4.非类型模板参数的限制和陷阱&#xff1a;5.几个问题 二、模板的特化1.概念2.函数模板特化3.类模板特化(1)全特化(2)偏特化(3)类模板特化应用示例 三、模板分离编译1.…