STL(Standard Template Library)标准模板库提供了模板适配器和迭代器等重要概念,为开发者提供了高效、灵活和方便的编程工具。模板适配器是指一组模板类或函数,它们提供一种适配机制,使得现有的模板能够适应新的需求。而迭代器则是STL中的令一种重要的概念,它是一个抽象化的数据访问机制,通过迭代器可以遍历STL容器中的元素。适配器与迭代器两者的紧密配合,使得开发者能够高效地处理容器中的元素,提高了代码的复用性和可维护性。

10.1 函数对象适配器

Bind2nd 是一个函数适配器,可以用来将一个双参函数转换成一个单参函数。使用该适配器可以修改函数中的第二个参数,而将第一个参数保持不变。

bind2nd 适配器的具体用法如下:

template <class Operation>
typename binder2nd<Operation>::type
bind2nd(const Operation& op, const typename Operation::second_argument_type& arg);

其中,Operation是一个二元操作函数对象类型(例如,std::less),而arg是该函数中的第二个参数。

bind2nd 会返回一个binder2nd类型的函数对象,它是一个可调用的单参函数对象,可以代替原始的双参函数对象,并将该函数对象的第二个参数固定为arg,从而实现单参数函数的调用。

如下所示,这段代码实现了绑定参数实现对函数对象的适配,使之可以传递参数,其定义了一个名为MyPrint的类,它继承自二元函数对象类binary_function,并重载了operator()操作符。通过模板参数,指定第一个参数类型为int,第二个参数类型也为int,返回值类型为void。在operator()中,对两个int类型的参数valstart进行加法运算,并输出结果到控制台。

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> using namespace std; // binary_function (val= > 参数类型1 start=> 参数类型2 void=> 返回值类型)
class MyPrint :public binary_function<int,int,void>
{
public:void operator()(int val, int start) const {
cout << val + start << endl;
}
}; int main(int argc, char* argv[])
{
vector<int> var = {1,2,3,4,5,6,7,8,9,10}; int num;
cin >> num; // 让MyPrint函数绑定num参数,传参是传递到MyPrint中
for_each(var.begin(), var.end(), bind2nd(MyPrint(),num));
system("pause");
return 0;
}

10.2 函数指针适配器

Ptr_fun 是一个函数适配器,可以将普通函数转换为函数对象(Functor),从而使得可以以函数对象的方式调用该函数。它通常用于STL提供的算法函数(如 sort、find等),这些算法函数要求传入的参数为函数对象,而普通函数并不满足这个要求。

使用ptr_fun的一般步骤为:

  • 在定义函数时,将函数声明为普通函数类型。
  • 在使用ptr_fun适配器时,通过参数列表将想要转换的函数名作为参数传入ptr_fun中。
  • 将得到的适配后的函数对象作为参数传递给调用该函数的算法函数。

下面是一个简单的例子,当函数无法直接绑定参数是,可以将函数指针适配为函数对象,然后再向内部传递参数:

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> using namespace std; void MyPrint(int val,int start)
{
cout << val + start << " ";
} int main(int argc, char* argv[])
{
vector<int> var = {1,2,3,4,5,6,7,8,9,10}; for_each(var.begin(), var.end(),bind2nd(ptr_fun(MyPrint),100) );
system("pause");
return 0;
}

10.3 容器取反适配器

Not1 是一个函数适配器,用于生成一个新函数对象,将原函数对象的逻辑取反。在使用not1这个适配器时,需要注意函数对象必须是一个一元谓词,也就是说,只接受一个参数并返回布尔值的函数对象。适配后的新函数对象接受一个参数,它的返回值取决于原函数对象的返回值,并将其取反。

以下是 not1 适配器的定义:

template <typename Predicate>
std::unary_negate<Predicate> not1(const Predicate& pred);

其中Predicate是一个一元谓词,而返回值是一个封装了谓词的std::unary_negate对象,它是一个可调用的函数对象,并可以在STL的算法函数中使用。

下面是一个使用not1的例子,我们想要找到第一个大于5的数是多少,但由于加上了not1取反,则输出的数据为小于5的数据。

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> using namespace std; class MyPrint : public unary_function<int,bool>
{
public:bool operator()(int val) const {
return val > 5; // 找大于5的数
}
}; int main(int argc, char* argv[])
{
vector<int> var = {1,2,3,4,5,6,7,8,9,10}; // 寻找第一个大于5的数,并遍历出来
vector<int>::iterator pos = find_if(var.begin(), var.end(), not1(MyPrint()));
if (pos != var.end())
cout << *pos << endl; system("pause");
return 0;
}

10.4 文件流对象拷贝文件

Istream_iterator 和 Ostream_iterator 是STL提供的两种迭代器适配器,它们分别用于将输入流和输出流封装成迭代器的形式,以便于使用STL提供的算法函数处理输入和输出流。

  • istream_iterator 可以通过重载 *、++== 等操作符,从输入流中读取数据,并形成一个可遍历的数据集合。
  • ostream_iterator 可以被用于将某个容器的元素写入输出流,它们提供了一个高效的方式,通过大量数据时不需要定义临时的缓冲区,而是直接将元素写入到流里,这使得它成为了输出大量数据时的好选择。

如下一段代码展示了通过绑定istream输入流对象,实现向前迭代动态拷贝文件到指定目录下的功能实现。

#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <algorithm> using namespace std; void Copy_Log(string src_path, string dst_path)
{
ifstream read_file;
ofstream write_file; read_file.open(src_path, ios::in);
read_file >> noskipws;
write_file.open(dst_path, ios::out); istream_iterator<char> iter_iFile(read_file);
ostream_iterator<char> iter_oFile(write_file); copy(iter_iFile, istream_iterator<char>(), iter_oFile);
} int main(int argc, char* argv[])
{
Copy_Log("c:\\lyshark.txt", "c:\\new.txt");
system("pause");
return 0;
}

10.5 向前/后插入迭代器

Front_insert_iterator 和 Back_insert_iterator 是两种STL提供的迭代器适配器,主要用于实现容器的插入操作。

back_inserter适配器可以将元素插入到容器的尾部,而front_inserter则是将元素插入到容器的头部。这两种适配器都是在使用中间层的帮助下实现容器的插入操作,其主要作用是在输出迭代器(通常是一个容器)的末尾自动添加新的元素。

  • back_insert_iterator:将元素追加到容器的末尾,实现方式是通过调用容器的push_back函数实现。
  • front_insert_iterator:将元素插入到容器的头部,实现方式是通过调用容器的push_front函数实现。

下面是具体用例,通过使用插入迭代器我们可以将一组数据插入到容器中的前或后等位置。

#include <iostream>
#include <iterator>
#include <set>
#include <deque>
#include <vector>
#include <algorithm> using namespace std; int main(int argc, char* argv[])
{
// 插入迭代器: 将两个数组合并,并插入到集合容器st中
int iArray1[] = { 1, 3, 5, 7, 9 };
int iArray2[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
set<int> st; merge(iArray1, iArray1 + 5, iArray2, iArray2 + 8, insert_iterator<set<int>>(st,st.begin()));
copy(st.begin(), st.end(), ostream_iterator<int>(cout, " ")); // 输出 st 内部的元素结果
cout << endl; // 向前插入迭代器
deque<int> deq = {1,2,3};
front_insert_iterator<deque<int>> fii(deq); // 向前插入
*fii++ = 0;
*fii++ = -1;
copy(deq.begin(), deq.end(), ostream_iterator<int>(cout, " ")); // 输出 deq 内部的元素结果
cout << endl; // 向后插入迭代器
int iArray3[] = { 1, 2, 3, 4 };
int len = sizeof(iArray3) / sizeof(int);
vector<int> ve = {5,6}; // 将数组元素从后插入到ve容器中
copy(iArray3,iArray3+len,back_insert_iterator<vector<int>>(ve));
copy(ve.begin(), ve.end(), ostream_iterator<int>(cout, " ")); // 输出 deq 内部的元素结果 system("pause");
return 0;
}

10.6 容器反向迭代器

Reverse_iterator 是STL提供的一种用于反向迭代器的适配器。它能够处理正向容器,并将其转换为反向容器,这使得可以使用STL通用算法从容器的末尾向前遍历。

一个reverse_iterator对象接受一个普通迭代器参数,并将该迭代器反转。如此一来,通过++运算符将使迭代器指向前一个元素,而*运算符返回的是它所指向的下一个元素。

下面是reverse_iterator的定义:

template<class Iterator>
class reverse_iterator {
public:
typedef std::reverse_iterator<Iterator> reverse_iterator; // C++11 typedef Iterator iterator_type;
typedef typename Iterator::iterator_category iterator_category;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::difference_type difference_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference; // 构造函数
reverse_iterator();
explicit reverse_iterator(typename iterator_type::pointer p);
explicit reverse_iterator(const iterator_type& x);
template<class U>
reverse_iterator (const reverse_iterator<U>& rev_it); // C++11 // 迭代器操作
reverse_iterator& operator++();
reverse_iterator operator++(int);
reverse_iterator& operator--();
reverse_iterator operator--(int);
reverse_iterator operator+ (difference_type n) const;
reverse_iterator& operator+= (difference_type n);
reverse_iterator operator- (difference_type n) const;
reverse_iterator& operator-= (difference_type n);
reference operator[](difference_type n) const;
pointer operator->() const;
reference operator*() const;
iterator_type base() const; // 友元函数
template<class U>
friend class reverse_iterator;
template<class U>
bool operator== (const reverse_iterator<U>& rhs) const;
template<class U>
bool operator!= (const reverse_iterator<U>& rhs) const;
};

下面是一个使用reverse_iterator的例子,该迭代器是一个用随机访问迭代器构造出来的迭代器,用于反向迭代容器元素。

#include <iostream>
#include <iterator>
#include <vector>
#include <list>
#include <algorithm> using namespace std; int main(int argc, char* argv[])
{
vector<int> var;
back_insert_iterator< vector<int>> bii(var);
*bii++ = 3;
*bii++ = 9;
*bii++ = 10; // 反向迭代器定义
reverse_iterator<vector<int>::iterator> rfirst(var.end());
reverse_iterator<vector<int>::iterator> rend(var.begin()); // 从尾到头打印
copy(rfirst, rend, ostream_iterator<int>(cout, " ")); system("pause");
return 0;
}

10.1 C++ STL 模板适配与迭代器的更多相关文章

  1. 泛型编程、STL的概念、STL模板思想及其六大组件的关系,以及泛型编程(GP)、STL、面向对象编程(OOP)、C++之间的关系

    2013-08-11 10:46:39 介绍STL模板的书,有两本比较经典: 一本是<Generic Programming and the STL>,中文翻译为<泛型编程与STL& ...

  2. stl之容器、迭代器、算法几者之间的关系

    转自:https://blog.csdn.net/bobodem/article/details/49386131 stl包括容器.迭代器和算法: 容器 用于管理一些相关的数据类型.每种容器都有它的优 ...

  3. C++ 泛型程序设计与STL模板库(1)---泛型程序设计简介及STL简介与结构

    泛型程序设计的基本概念 编写不依赖于具体数据类型的程序 将算法从特定的数据结构中抽象出来,成为通用的 C++的模板为泛型程序设计奠定了关键的基础 术语:概念 用来界定具备一定功能的数据类型.例如: 将 ...

  4. [深入浅出Windows 10]不同平台设备的适配

    2.3 不同平台设备的适配 Windows 10通用应用程序针对特定的平台还会有一个子API的集合,当我们要使用到某个平台的特定API的时候(比如手机相机硬件按钮触发事件),这时候就需要调用特定平台的 ...

  5. DLL中导出STL模板类的问题

    接上一篇. 上一篇的dll在编译过程中一直有一个警告warning C4251: ‘CLASS_TEST::m_structs’ : class ‘std::vector<_Ty>’ ne ...

  6. SGI STL红黑树中迭代器的边界值分析

    前言 一段程序最容易出错的就是在判断或者是情况分类的边界地方,所以,应该对于许多判断或者是情况分类的边界要格外的注意.下面,就分析下STL中红黑树的迭代器的各种边界情况.(注意:分析中STL使用的版本 ...

  7. C++STL模板库适配器之优先级队列

    目录 适配器之优先级队列 一丶优先级队列简介(priority_queue) 二丶优先级队列代码演示 1.优先级队列代码以及使用简介 适配器之优先级队列 一丶优先级队列简介(priority_queu ...

  8. C++STL模板库适配器之queue队列

    目录 适配器之队列 一丶队列简介 二丶队列(queue)代码操作 1.常用方法 适配器之队列 一丶队列简介 队列是先进先出的数据结构. 在STL中使用 queue表示. 底层使用的是序列容器deque ...

  9. C++STL模板库适配器之stack容器

    目录 适配器 一丶适配器简介 二丶栈(stack)用法 1.栈的常用方法 适配器 一丶适配器简介 Stl中的适配器,有栈 (stack) 队列 queue 根priority_queue 适配器都是包 ...

  10. STL模板_容器概念

    一.STL(Standard Template Library,标准模板库)概述1.容器:基于泛型的数据结构.2.算法:基于泛型的常用算法.3.迭代器:以泛型的方式访问容器中的元素,是泛型的算法可以应 ...

随机推荐

  1. 如何利用CCXT交易数字货币合约

    更多精彩内容,欢迎关注公众号:数量技术宅,也可添加技术宅个人微信号:sljsz01,与我交流. 对于币圈量化老司机来说,相信或多或少都有接触过ccxt这个接口,ccxt为我们提供了多交易所统一的标准格 ...

  2. ITS实现可滚动表格

    一.ITS不支持TableControl 在ITS条码开发中,遇到需要滚动浏览表格的需求,但是在ITS中是不支持TableControl,并且已经验证在PDA中显示ALV行不通,因为ALV条目过多无法 ...

  3. POJ 1236 Network of Schools (连通图 - Garbow 算法)

    POJ 1236 Network of Schools ​ 校园网:给定N所学校和网络,目标是分发软件其他学校都可收到,求①所需最少分发学校数:②若任选学校都能收到,最低新增边数. 思路:同一个强连通 ...

  4. CH6803 导弹防御塔 (二分 + 匈牙利 / 网络流)

    链接:https://ac.nowcoder.com/acm/contest/1062/D 题目描述 Freda的城堡-- "Freda,城堡外发现了一些入侵者!" "喵 ...

  5. Go 标准库 net

    本篇文章主要介绍 Go 标准库中的 net 包,通过一个小例子介绍常用的 net 包函数/方法 Listen,Accept 和 Dial 等. 1. net 简介 Go 官网对 net 包的定义如下: ...

  6. 概率图模型 · 蒙特卡洛采样 · MCMC | 非常好的教学视频

    https://www.bilibili.com/video/BV17D4y1o7J2?p=1 非常感谢!感觉学会一点了,应该能写作业了

  7. SV 数据类型-3

    联合数组 在内存中分配的空间可以是不连续的 联合数组方法 数组的方法 数组使用推荐 结构体 枚举类型 字符串变量类型String 操作符

  8. 17-三态门(TSL)

    三态门(TSL) 普通的逻辑电路只有两个状态,还有一个高阻态. EN是高电平1 A,B,EN之间的关系是与的关系,当EN为1得时候,EN就不起作用了,输入由A,B决定.EN端为高电平,所以二极管D2截 ...

  9. 配置Maven项目时无法找到依赖

    1.问题 在配置pom.xml文件时,关于plugin插件配置时,遭遇许多类似 未找到插件 'maven-clean-plugin:3.1.0' 未找到插件 'org.apache.maven.plu ...

  10. 0xGame 2023【WEEK3】Crypto WP

    EzECC 1.题目信息 还在偷听小爱和小爆的通讯! Hint 1: 也许SageMath能给你想要的东西 Hint 2: 预期解法时间估计可能一两分钟左右,可能更短 Hint 3: 阿贝尔群上的加加 ...