C++ STL 适配器

2024-09-09 04:04
文章标签 c++ stl 适配器

本文主要是介绍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-streamcopy(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等

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

这篇关于C++ STL 适配器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1150109

相关文章

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

c++的初始化列表与const成员

初始化列表与const成员 const成员 使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。 不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。 在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。 初始化列表 在构造函数小括号后面,主要用于给

2024/9/8 c++ smart

1.通过自己编写的class来实现unique_ptr指针的功能 #include <iostream> using namespace std; template<class T> class unique_ptr { public:         //无参构造函数         unique_ptr();         //有参构造函数         unique_ptr(