首页 > 编程语言 >10.1 C++ STL 模板适配与迭代器

10.1 C++ STL 模板适配与迭代器

时间:2023-08-17 15:33:00浏览次数:43  
标签:10.1 函数 iterator STL 适配 int include 迭代 reverse

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;
}

本文作者: 王瑞 本文链接: https://www.lyshark.com/post/e6708835.html 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

标签:10.1,函数,iterator,STL,适配,int,include,迭代,reverse
From: https://blog.51cto.com/lyshark/7123286

相关文章

  • 11.1 C++ STL 应用字典与列表
    C++STL标准模板库提供了丰富的容器和算法,这些模板可以灵活组合使用,以满足不同场景下的需求。本章内容将对前面学习的知识进行总结,并重点讲解如何灵活使用STL中的vector和map容器,以及如何结合不同的算法进行组合。通过灵活组合使用这些容器和算法,能够满足不同场景下的需求,实现高......
  • 9.1 C++ STL 排序、算数与集合
    C++STL(StandardTemplateLibrary)是C++标准库中的一个重要组成部分,提供了丰富的模板函数和容器,用于处理各种数据结构和算法。在STL中,排序、算数和集合算法是常用的功能,可以帮助我们对数据进行排序、统计、查找以及集合操作等。STL提供的这些算法,能够满足各种数据处理和分析的需......
  • 11.1 C++ STL 应用字典与列表
    C++STL标准模板库提供了丰富的容器和算法,这些模板可以灵活组合使用,以满足不同场景下的需求。本章内容将对前面学习的知识进行总结,并重点讲解如何灵活使用STL中的vector和map容器,以及如何结合不同的算法进行组合。通过灵活组合使用这些容器和算法,能够满足不同场景下的需求,实现高......
  • centos7安装mariadb-10.10.6-linux-systemd-x86_64.tar.gz
    [root@kht100data]#mysql_install_db--user=root--basedir=/usr/local/mariadb--datadir=/usr/local/mariadb/dataInstallingMariaDB/MySQLsystemtablesin'/usr/local/mariadb/data'...2023-08-1711:07:360[Note]StartingMariaDB10.10.6-MariaDB......
  • Android实战:APP换肤功能,并自动适配手机深色模式
    Android换肤功能已不是什么新鲜事了,市面上有很多第三方的换肤库和实现方案。之所以选择腾讯的QMUI库来演示APP的换肤功能,主要原因:1、换肤功能的实现过程较简单、容易理解;2、能轻松适配Android10提供的DarkMode(深色模式);3、还能白嫖QMUI的各种组件、效果(这才是重要的,......
  • 移动端适配方案
    前置知识px像素单位px全称为pixel(像素),它是相对于屏幕显示器分辨率(桌面设定的分辨率,不是显示器的物理分辨率)而言的,在相同/不同的设备上1px表示多个设备像素。当一个像素点越大时,呈现的图像就会越模糊;当一个像素点越小时,像素点就会越密集,呈现的图像就会越清......
  • 6.1 C++ STL 序列映射容器
    Map/Multimap映射容器属于关联容器,它的每个键对应着每个值,容器的数据结构同样采用红黑树进行管理,插入的键不允许重复,但值是可以重复的,如果使用Multimap声明映射容器,则同样可以插入相同的键值。Map中的所有元素都会根据元素的键值自动排序,所有的元素都是一个Pair同时拥有实值和键......
  • 7.1 C++ STL 非变易查找算法
    C++STL中的非变易算法(Non-modifyingAlgorithms)是指那些不会修改容器内容的算法,是C++提供的一组模板函数,该系列函数不会修改原序列中的数据,而是对数据进行处理、查找、计算等操作,并通过迭代器实现了对序列元素的遍历与访问。由于迭代器与算法是解耦的,因此非变易算法可以广泛地应......
  • 8.1 C++ STL 变易拷贝算法
    C++STL中的变易算法(ModifyingAlgorithms)是指那些能够修改容器内容的算法,主要用于修改容器中的数据,例如插入、删除、替换等操作。这些算法同样定义在头文件<algorithm>中,它们允许在容器之间进行元素的复制、拷贝、移动等操作,从而可以方便地对容器进行修改和重组。主要包括以下......
  • 7.1 C++ STL 非变易查找算法
    C++STL中的非变易算法(Non-modifyingAlgorithms)是指那些不会修改容器内容的算法,是C++提供的一组模板函数,该系列函数不会修改原序列中的数据,而是对数据进行处理、查找、计算等操作,并通过迭代器实现了对序列元素的遍历与访问。由于迭代器与算法是解耦的,因此非变易算法可以广泛地应......