STL源码剖析:适配器

从零开始学C++之STL(九):函数适配器bind2nd 、mem_fun_ref 源码分析、函数适配器应用举例_从零开始学c++之stl(九):-CSDN博客

适配器(adapter)是一种设计模式,将一个 class 的接口转换为另一个 class 的接口,使原本因接口不兼容而不能合作的对象可以一起运作。适配器之所以能够工作,是因为adapter内部持有对象的副本,副本可以是容器、迭代器、流或者一个仿函数。通过对这个对象的封装,适配器可以控制对象的行为,并对其输入和输出进行必要的调整。这样,适配器就能够将原本不兼容的接口或功能转化成一个统一的形式,使其能够在标准库算法中使用。

比如container adaper内部定义了一个指向container的指针,(逆向)迭代器适配器内部定义了一个迭代器对象。

IOStream adaper内部定义了一个指向stream对象的指针

配接器分类
容器适配器

用来扩展7种基本容器,利用基本容器(deque,heap)扩展形成了stack、queue和prioriory_queue。

迭代器适配器

反向迭代器 reverse iterators,插入迭代器 insert iterators,IO流迭代器 iostream iterators)。

insert iterators

阅读材料:STL配接器原理详解------迭代器配接器(iterator adapters)-CSDN博客

insert iterators,可以将一般迭代器的赋值操作转换为插入操作 。每一个insert iterators内部都维护一个容器(由用户指定)。容器有自己的迭代器,对insert iterators做赋值时,就在insert iterators中被转换为对该容器的迭代器做插入操作。在insert iterators的operator=操作符中调用底层容器的push_front()、push_back()或insert() 操作函数,至于其他的迭代器行为例如:operator++,operator*,operator--,operator->都被关闭。

insert itertators的前进、后退、取值、成员取用等操作都是没有意义的。

insert itertators 专用于尾端插入操作的back_insert_iterator,专用于头端插入操作front_insert_iterator,在任意位置插入操作的insert_iterator。

由于上面三个iterator adapters的使用接口不是很直观,STL提供下图所示的三个函数。

back_insert_iterator类、back_inserter()函数

cpp 复制代码
// 这是一个迭代器配接器,用来将某个迭代器的赋值操作改为插入操作,改为从容器的尾端插入
template<class Container>
class back_insert_iterator{
protected:
    Container* container;//底层容器
public:
   typedef out_iterator_tag iterator_category;//注意类型
   typedef void             value_type;
   typedef void             difference_type;
   typedef void             pointer;
   typedef void             reference;
    //构造函数使back_insert_iterator与容器绑定起来
 explicit back_insert_iterator(Container& x):container(&x) {}
 back_insert_iterator<Container>& operator=(const typename Container::value_type& value){
        container->push_back(value);//这里是关键,直接调用push_back()
        return *this;
    }
    //下面的操作符对back_insert_iterator不起作用(关闭功能)
    //因此都返回自己
    back_insert_iterator<Container>& operator*() { return *this; }
    back_insert_iterator<Container>& operator++() { return *this; }
    back_insert_iterator<Container>& operator++(int) { return *this; }
};

back_insert_iterator类中,container成员变量是指向容器的一个指针。

front_insert_iterator类、front_inserter()函数

cpp 复制代码
//一个迭代器配接器,用来将某个迭代器的赋值操作改为插入操作------改为从容器的头部插入
//注意,该容器不支持vector,因为vector没有提供push_front()函数。
template<class Container>
class front_insert_iterator
{
protected:
    Container* container; //底层容器
public:
    typedef out_iterator_tag iterator_category; //注意类型
    typedef void             value_type;
    typedef void             difference_type;
    typedef void             pointer;
    typedef void             reference;
    //构造函数使back_insert_iterator与容器绑定起来
    explicit front_insert_iterator(Container& x) :container(&x) {}
    front_insert_iterator<Container>& operator=(const typename Container::value_type& value)
    {
        container->push_front(value);//这里是关键,直接调用push_front()
        return *this;
    }
    //下面的操作符对front_insert_iterator不起作用(关闭功能)
    //因此都返回自己
    front_insert_iterator<Container>& operator*() { return *this; }
    front_insert_iterator<Container>& operator++() { return *this; }
    front_insert_iterator<Container>& operator++(int) { return *this; }
};
cpp 复制代码
//这是一个辅助函数,方便我们使用front_insert_iterator
template<class Container>
inline front_insert_iterator<Container> front_inserter(Container& x){
    return front_insert_iterator<Container>(x);
}

insert_iterator类、inserter()函数

cpp 复制代码
//这是一个迭代器配接器,用来将某个迭代器的赋值操作改为插入操作------在任意位置上插入
//并将迭代器右移一个位置------如此便可以方便地连续插入
//表面上是赋值操作,实际上是插入操作
template<class Container>
class insert_iterator{
protected:
     Container* container; //底层容器
     typename Container::iterator iter;
public:
    typedef out_iterator_tag iterator_category; //注意类型
    typedef void             value_type;
    typedef void             difference_type;
    typedef void             pointer;
    typedef void             reference;
    insert_iterator(Container& x, typename Container::iterator i) 
        :container(&x), iter(i) {}
    insert_iterator<Container>& operator=(const typename Container::value_type& value){
       iter = container->inserter(iter, value); //关键,直接调用insert()
       ++iter; //使insert iterator永远随其目标而移动
       return *this;
    } 
    //下面的操作符对insert_iterator不起作用(关闭功能)
    //因此都返回自己
    insert_iterator<Container>& operator*() { return *this; }
    insert_iterator<Container>& operator++() { return *this; }
    insert_iterator<Container>& operator++(int) { return *this; }
};
reverse Iterators
  • Reverse Iterators,就是将一般迭代器的前进方向逆转:
    • 使原本应该前进的operator++变为后退操作
    • 使原本应该后退的operator--编程前进操作
  • 如果STL算法接受的不是一般的迭代器,而是这种逆向迭代器,它就会从尾到头的方向来处理序列中的元素。
cpp 复制代码
使用迭代器模式理解这个过程:

//迭代器配接器,用来将某个迭代器逆反前进方向
template<class Iterator>
class reverse_iterator{
protected:
   Iterator current;  /记录对应的正向迭代器
public:
    //5中与迭代器相关的类型
 typedef typname iterator_traits<Iterator>::iterator_category iterator_category;
 typedef typname iterator_traits<Iterator>::value_type value_type;
    typedef typname iterator_traits<Iterator>::difference_type difference_type;
    typedef typname iterator_traits<Iterator>::pointer pointer;
    typedef typname iterator_traits<Iterator>::reference reference;
    typedef Iterator iterator_type;          //正向迭代器
    typedef reverse_iterator<Iterator> self; //逆向迭代器
public:
    reverse_iterator() {}
    //将reverse_iterator与某个迭代器x关联起来
   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;
        //以上关键在于。对逆向迭代器取值,"对应的正向迭代器"后退一位取值
    }
   pointer operator->()const { return &(operator*()); }//意义同上 
//前进变后退
   self& operator++() {
       --current; ++*this;
   }
   self operator++(int) {
       self tmp = *this; --current; return tmp;
   }
//后退变前进
   self& operator--() {
       ++current; ++*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;
    }
    //下面第一个*和唯一一个+都会调用本类的operator*和operator+
    //第二个*则不会
    reference operator[](difference_type n)const { return*(*this + n); }
};
IOStream Iterators

IOStream Iterators将输入和输出流(如 std::cinstd::cout、文件流等)适配成符合标准迭代器接口的对象,使这些流可以与 C++ 标准库算法无缝地协同工作。

(1)绑定istream对象(如cin)的迭代器称为istream_iterator,istream_iterator将输入流适配成一个输入迭代器,使其可以像普通的迭代器一样通过递增操作(++)读取数据并通过解引用(*)访问当前值。

(2)绑定ostream(如cout)的迭代器称为ostream_iterator,将输出流适配成一个输出迭代器,使其可以像普通的输出迭代器一样通过赋值操作将数据写入流中,这些迭代器将它们对应的流当做一个特定类型的元素序列来处理。

istream_iterator

源码简化

cpp 复制代码
template <class T, class Distance = ptrdiff_t>
class istream_iterator {
    friend bool operator==(/* 参数 */); // 用于比较两个迭代器是否相等
protected:
    istream* stream;    // 指向输入流的指针
    T value;            // 当前读取的值
    bool end_marker;    // 标记是否到达输入的结束
    void read();        // 用于从输入流读取数据
public:
    // 定义了一些迭代器的类型
    typedef input_iterator_tag iterator_category;
    typedef T value_type;
    typedef Distance difference_type;
    typedef const T* pointer;
    typedef const T& reference;
    // 构造函数
    istream_iterator();
    istream_iterator(istream& s);
    // 迭代器的解引用操作
    reference operator*() const;
    pointer operator->() const;
    // 迭代器的前置和后置递增操作
    istream_iterator<T, Distance>& operator++();
    istream_iterator<T, Distance> operator++(int);
};

istresm iterator对istream对象做了封装,因为是STL迭代器,所以需要定义一些迭代器类型相关的变量(C++ 标准库对迭代器类型的要求。标准库中定义的迭代器类型通常会包含一组类型别名,用于描述迭代器的性质和行为),然后重写解引用,++等操作(调用istream对象)。

创建与初始化

创建一个输入流迭代器时,必须指定迭代器将要读取的数据的类型。因为istream_iterator使用>>读取流,因此创建istream_iterator对象时必须使用输入流对象初始化它。当然也可以默认初始化迭代器,这样创建一个可以当做尾后值使用的迭代器。

cpp 复制代码
#include <iostream>
#include <fstream>
#include <iterator>
#include <string>
int main() {
    // 从标准输入读取整数
    std::istream_iterator<int> int_it(std::cin); // 使用 cin 初始化读取整数的迭代器
    std::istream_iterator<int> int_eof;          // 尾后迭代器,用于检测输入结束
    std::cout << "Reading integers from standard input (type any non-integer to stop):\n";
    while (int_it != int_eof) {
        std::cout << "You entered: " << *int_it << std::endl;
        ++int_it; // 递增迭代器,读取下一个整数
    }
    // 从文件中读取字符串
    std::ifstream in("afile.txt");
    if (!in) {
        std::cerr << "Failed to open the file.\n";
        return 1;
    }
    std::istream_iterator<std::string> str_it(in);  // 使用文件流初始化读取字符串的迭代器
    std::istream_iterator<std::string> str_eof;     // 尾后迭代器,用于检测文件读取结束
    std::cout << "Reading strings from file 'afile.txt':\n";
    while (str_it != str_eof) {
        std::cout << "Read string: " << *str_it << std::endl;
        ++str_it; // 递增迭代器,读取下一个字符串
    }
    return 0;
}

尾后迭代器是指向容器末尾的一个位置的迭代器,这个位置并不存储任何实际的数据。它主要用于标识容器的结束,通常用于在循环或算法中检测是否已经遍历完所有元素。因为流迭代器类似于一个容器,保存了我们输入的数据,因此可以使用下面的方式对一个vec进行构造。

cpp 复制代码
//阻塞在此处,从cin中读取数据
std::istream_iterator<int> in_iter(std::cin);
std::istream_iterator<int> eof; 
//从迭代器范围构造vec
std::vector<int> vec(in_iter, eof);
for (auto val : vec) { std::cout << val << " ";}

我们可以在算法中使用istream_iterator迭代器,如accumulate()算法的参数1和参数2表示一个迭代器范围,参数3为初始值,此算法将迭代器所指的范围内的元素与初始值加在一起返回总和。

cpp 复制代码
//阻塞在此处,从cin中读取数据
std::istream_iterator<int> in_iter(std::cin);
std::istream_iterator<int> eof;
将in_iter, eof内的元素做总和,以0为初始值
std::cout << std::accumulate(in_iter, eof, 0) << std::endl;

ostream_iterator

源码简化

cpp 复制代码
template <class T>
class ostream_iterator {
protected:
    ostream* stream;           // 指向输出流的指针
    const char* string;        // 每次输出后的间隔符号
public: 
//定义了迭代器的类型
    typedef output_iterator_tag iterator_category;
    typedef void value_type;
    typedef void difference_type;
    typedef void pointer;
    typedef void reference;
//构造函数
    ostream_iterator(ostream& s) : stream(&s), string(0) {}
    ostream_iterator(ostream& s, const char* c) : stream(&s), string(c) {}
//赋值操作符,用于将数据输出到流中
    ostream_iterator<T>& operator=(const T& value) {
        *stream << value;        // 输出数据到流
        if (string) *stream << string;  // 输出间隔符
        return *this;
    }
//以下操作符对输出迭代器没有实际效果,但需要提供以符合迭代器接口
    ostream_iterator<T>& operator*() { return *this; }
    ostream_iterator<T>& operator++() { return *this; }
    ostream_iterator<T>& operator++(int) { return *this; }
};

ostream iterator封装了ostream对象,然后根据STL对迭代器标准定义了一些类型变量,然后重载赋值运算符将数据输出到ostream中,*,++都没有效果。

创建与初始化

创建一个输出流迭代器时,必须指定迭代器将要输出的数据的类型。ostream_iterator使用<<输出数据,因此创建ostream_iterator对象时其参数1必须指定一个输出流对象,另外其还有一个参数2,这个参数是一个字符串类型(必须是C风格的字符串),在输出每个元素后都会打印此字符串。另外不允许有类似于istream_iterator的尾后迭代器,因此不允许有默认初始化。

cpp 复制代码
std::vector<int> vec{ 1,2,3 };
//输出流迭代器操作的元素类型为int,使用cout作为初始化
std::ostream_iterator<int> out_iter(std::cout, " ");
//for循环每执行一次,从vec中取出一个元素赋值给out_iter,然后out_iter进行输出
for (auto val : vec) {
    out_iter = val;
}
std::cout << std::endl;

可以在算法中使用,使用copy()算法将vector的元素拷贝进输出流迭代器对象中进行输出。

cpp 复制代码
std::vector<int> vec{ 1,2,3 };
std::ostream_iterator<int> out_iter(std::cout, " ");
std::copy(vec.begin(), vec.end(), out_iter);
std::cout << std::endl;

三种迭代器的综合使用:

cpp 复制代码
#include<iterator>  // for iterator adapters
#include<deque>
#include<algorithm> // for copy, find
#include<iostream>
using namespace std;
int main() {
    // 创建一个 ostream_iterator 绑定到 cout,每次输出元素后跟一个空格
    ostream_iterator<int> outite(cout, " ");
    int ia[] = {0, 1, 2, 3, 4, 5};
    deque<int> id(ia, ia + 6);
    // 将所有元素拷贝到 outite (即拷贝到 cout)
    copy(id.begin(), id.end(), outite); // 输出: 0 1 2 3 4 5
    cout << endl;
    // 使用 front_insert_iterator 将 ia 的部分元素拷贝到 id 内
    // 注意:front_insert_iterator 会将 assign 操作改为 push_front 操作
    copy(ia + 1, ia + 2, front_inserter(id));
    copy(id.begin(), id.end(), outite); // 输出: 1 0 1 2 3 4 5
    cout << endl;
    // 使用 back_insert_iterator 将 ia 的部分元素拷贝到 id 内
    copy(ia + 3, ia + 4, back_inserter(id));
    copy(id.begin(), id.end(), outite); // 输出: 1 0 1 2 3 4 5 3
    cout << endl;
    // 搜寻元素 5 所在位置
    deque<int>::iterator ite = find(id.begin(), id.end(), 5);
    // 使用 insert_iterator 在找到的位置前插入 ia 的部分元素
    copy(ia + 0, ia + 3, inserter(id, ite));
    copy(id.begin(), id.end(), outite); // 输出: 1 0 1 2 3 4 0 1 2 5 3
    cout << endl;
    // 将所有元素逆向拷贝到 outite
    copy(id.rbegin(), id.rend(), outite); // 输出: 3 5 2 1 0 4 3 2 1 0 1
    cout << endl;
    // 创建一个 istream_iterator 绑定到 cin,直到遇到 end-of-stream
    istream_iterator<int> inite(cin), eos; // eos: end-of-stream
    // 从标准输入读取整数并插入到 id 的开始位置
    copy(inite, eos, front_inserter(id));
    // 输出最终的 deque 内容
    copy(id.begin(), id.end(), outite);
    cout << endl;
    return 0;
}
函数适配器

函数适配器能够将仿函数和另一个仿函数(或某个值或某个一般函数)结合起来。

cpp 复制代码
// 计算奇数元素的个数 这里的bind2nd将二元函数对象modulus转换为一元函数对象。
// bind2nd(op,value)(param) 相当于 op(param, value)
cout<<count_if(v.begin(), v.end(),bind2nd(modulus< int>(),  2))<< endl;

在STL(标准模板库)中,仿函数适配器(functor adapter)是一种特殊的类模板,可以修改现有的仿函数(functor)的行为,包括绑定参数、否定执行结果或组合多个函数等。

仿函数是重载了 operator() 的类对象,它可以像普通函数一样被调用。而仿函数适配器则是在原有仿函数的基础上添加了一层抽象,使得可以预设一些行为,预设的行为将在实际使用时影响仿函数的操作。

常见的仿函数适配器

Binder:std::bind1st 和 std::bind2nd 是两个用于绑定仿函数参数的适配器。它们允许将一个二元仿函数转换为一元仿函数,通过固定其中一个参数来达到目的。

例如,如果有一个比较两个整数的仿函数 less<int>(),可以使用bind2nd(less<int>(),12)来创建一个新的仿函数,这个新仿函数会检查其输入是否小于 12。

Negator:std::not1 和 std::not2 是用来对仿函数的结果取反的适配器。如果原始仿函数返回布尔值,那么使用这些适配器后,仿函数将会返回相反的布尔值。

Composer:std::unary_negate 和 std::binary_negate 可以用来构造新的仿函数,该仿函数会对原仿函数的结果进行逻辑非操作。另外,还有其他更复杂的组合方式,比如使用 std::compose1 和 std::compose2 来组合两个仿函数,形成一个新的复合仿函数。

Other Adapters:还有一些其他的适配器,如 std::ptr_fun 可以将普通的函数指针转换为仿函数,这样就可以让普通的C风格函数也能与STL算法一起工作。

当使用仿函数适配器时,实际上是在创建一个新的对象,这个对象内部持有一个指向原来仿函数的引用或副本。当这个适配器对象被调用时,它会按照预设的方式调用内部持有的仿函数,并根据需要处理参数和返回值。因此,虽然看起来像是在调用适配器对象,但实际上是在间接地调用并控制着原来的仿函数。

对返回值进行逻辑否定:not1, not2
cpp 复制代码
// 以下配接器用来表示某个 Adaptable Predicate 的逻辑负值(logical negation)
template <class Predicate>
class unary_negate : public std::unary_function<typename Predicate::argument_type, bool> {
protected:
    Predicate pred; // 内部成员 Predicate
public:
    explicit unary_negate(const Predicate& x) : pred(x) {} // 构造函数
    bool operator()(const typename Predicate::argument_type& x) const { // 重载 () 运算符
        return !pred(x); // 将 pred 的运算结果加上否定(negate)运算
    }
};
// 辅助函数,使我们得以方便使用 unary_negate<Predicate>
template <class Predicate>
inline unary_negate<Predicate> not1(const Predicate& pred) {
    return unary_negate<Predicate>(pred);
}
// 以下配接器用来表示某个 Adaptable Binary Predicate 的逻辑负值
template <class Predicate>
class binary_negate : public std::binary_function<
typename Predicate::first_argument_type,typename Predicate::second_argument_type,
bool>
{
protected:
    Predicate pred; // 内部成员 Predicate
public:
    explicit binary_negate(const Predicate& x) : pred(x) {} // 构造函数
    bool operator()(
        const typename Predicate::first_argument_type& x,
        const typename Predicate::second_argument_type& y
    ) const { // 重载 () 运算符
        return !pred(x, y); // 将 pred 的运算结果加上否定(negate)运算
    }
};
//辅助函数,使我们得以方便使用 binary_negate<Predicate>
template <class Predicate>
inline binary_negate<Predicate> not2(const Predicate& pred) {
    return binary_negate<Predicate>(pred);
}
对参数进行绑定:bind1st,bind2nd
cpp 复制代码
template <class Operation>
class binder1st : public std::unary_function<
    typename Operation::second_argument_type,
    typename Operation::result_type>{
protected:
    Operation op; // 内部成员
    typename Operation::first_argument_type value; // 内部成员
public:
    // 构造函数
binder1st(const Operation& x, const typename Operation::first_argument_type& y)
        : op(x), value(y) {} // 将表达式和第一参数记录于内部成员
    // 重载 () 运算符
typename Operation::result_type operator()(
        const typename Operation::second_argument_type& x) const {
        return op(value, x); // 实际调用表达式,并将 value 绑定为第一参数
 }
};
// 辅助函数,使我们得以方便使用 binder1st<Operation>
template <class Operation, class T>
inline binder1st<Operation> bind1st(const Operation& op, const T& x) {
   typedef typename Operation::first_argument_type arg1_type;
   return binder1st<Operation>(op, arg1_type(x)); // 先把x转型为 op 的第一参数型别
}
// 以下配接器用来将某个 Adaptable Binary Function 转换为 Unary Function
template <class Operation>
class binder2nd : public std::unary_function<
    typename Operation::first_argument_type,
    typename Operation::result_type>{
protected:
    Operation op; // 内部成员
    typename Operation::second_argument_type value; // 内部成员
public:
    // 构造函数
    binder2nd(const Operation& x, const typename Operation::second_argument_type& y)
        : op(x), value(y) {} // 将表达式和第二参数记录于内部成员
    // 重载 () 运算符
    typename Operation::result_type operator()(
        const typename Operation::first_argument_type& x) const {
        return op(x, value); // 实际调用表达式,并将 value 绑定为第二参数
    }
};
// 辅助函数,使我们得以方便使用 binder2nd<Operation>
template <class Operation, class T>
inline binder2nd<Operation> bind2nd(const Operation& op, const T& x) {
    typedef typename Operation::second_argument_type arg2_type;
    return binder2nd<Operation>(op, arg2_type(x)); // 先把x转型为 op 的第二参数型别
}
用于函数合成:compose1,compose2
cpp 复制代码
// 已知两个 Adaptable Unary Functions f(),g(),以下配接器用来产生一个 h(),
// 使 h(x)= f(g(x))
template <class Operation1,class Operation2>
class unary_compose
: public unary_function<typename Operation2::argument_type,
typename Operation1::result_type>{
protected:
  // 内部成员 
   Operation1 op1;
  //内部成员 
   Operation2 op2;
public:
  //constructor
 unary_compose(const Operation1& x, const Operation2& y):op1(x),op2(y){}
 // 将两个表达式记录于内部成员
 typename Operation1::result_type operator()
  (const typename Operation2::argument_type& x) const {
 //函数合成 
    return opl(op2(x));
  }
};

// 辅助函数,让我们得以方便运用 unary_compose<0p1,Op2>
template <class Operation1,class operation2>
inline unary_compose<Operation1,Operation2>
 compose1(const Operation1& opl,const Operation2& op2){
   return unary_compose<0peration1,Operation2>(op1,op2);
}

// 已知一个 Adaptable Binary Function f 和
// 两个 Adaptable Unary Functions g1,g2,
//以下配接器用来产生一个 h,使 h(x)= f(g1(x),g2(x))
template <class Operation1,class Operation2,class Operation3>
class binary_compose:public unary_function<typename Operation2::argument_type,
typename Operationl::result_type> {
protected:
// 内部成员 
  Operation1 op1;
// 内部成员 
  Operation2 op2;
// 内部成员 
  Operation3 op3;
public:
//constructor,将三个表达式记录于内部成员
  binary_compose(const Operation1& x, const Operation2& y,const Operation3& z):
  op1(x),op2(y),op3(z){}
  typename Operation1::result_type
   operator()(const typename Operation2:sargument_type& x) const{
//函数合成 
   return opl(op2(x),op3(x));
}
};
// 辅助函数,让我们得以方便运用 binary_compose<0p1,0p2,0p3>
template <class Operation1,class Operation2,class Operation3>
inline binary_compose<Operation1, Operation2,operation3>
compose2(const Operation1& opl,const Operation2& op2,
const Operation3& op3){
return binary_compose<Operation1,Operation2,Operation3>
(op1,op2,op3)
}

unary_compose类模板

unary_compose 用来将两个一元函数(Adaptable Unary Functions)组合成一个新的函数。这个新的函数首先应用第二个函数(op2),然后将结果传递给第一个函数(op1)。这样,新函数 h(x) 的行为是 h(x) = f(g(x))

binary_compose类模板

binary_compose 用来将一个二元函数和两个一元函数组合成一个新的函数。这个新的函数首先分别应用两个一元函数(op2op3),然后将它们的结果作为参数传递给二元函数(op1)。这样,新函数 h(x) 的行为是 h(x) = f(g1(x), g2(x))

用于函数指针:ptr_fun

函数指针不能直接传入STL算法的参数,需要使用函数适配器把他包装成仿函数使用。

cpp 复制代码
#include <functional> // 为了使用 std::unary_function 和 std::binary_function
// 以下配接器其实就是把一个一元函数指针包起来:
// 当仿函数被使用时,就调用该函数指针
template <class Arg, class Result>
class pointer_to_unary_function : public std::unary_function<Arg, Result> {
protected:
    Result (*ptr)(Arg); // 内部成员,一个函数指针
public:
    pointer_to_unary_function() : ptr(nullptr) {} // 默认构造函数
    // 以下 constructor 将函数指针记录于内部成员之中
    explicit pointer_to_unary_function(Result (*x)(Arg)) : ptr(x) {}
    // 以下,通过函数指针执行函数
    Result operator()(Arg x) const { return ptr(x); }
};
// 辅助函数,让我们得以方便运用 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 Arg1, class Arg2, class Result>
class pointer_to_binary_function : public std::binary_function<Arg1, Arg2, Result> {
protected:
    Result (*ptr)(Arg1, Arg2); // 内部成员,一个函数指针
public:
    pointer_to_binary_function() : ptr(nullptr) {} // 默认构造函数
    // 以下 constructor 将函数指针记录于内部成员之中
    explicit pointer_to_binary_function(Result (*x)(Arg1, Arg2)) : ptr(x) {}
    // 以下,通过函数指针执行函数
    Result operator()(Arg1 x, Arg2 y) const { return ptr(x, y); }
};
// 辅助函数,让我们得以方便使用 pointer_to_binary_function
template <class Arg1, class Arg2, class Result>
inline pointer_to_binary_function<Arg1, Arg2, Result> ptr_fun(Result (*x)(Arg1, Arg2)) {
    return pointer_to_binary_function<Arg1, Arg2, Result>(x);
}
用于成员函数指针:mem_fun,mem_fun_ref
cpp 复制代码
// 基类 Shape
class Shape {
public:
    virtual void display() = 0; // 纯虚函数
    virtual ~Shape() {} // 虚析构函数,确保派生类对象被正确销毁
};
// 派生类 Rect
class Rect : public Shape {
public:
    void display() override { cout << "Rect "; }
};
// 派生类 Circle
class Circle : public Shape {
public:
    void display() override { cout << "Circle "; }
};
// 派生类 Square,继承自 Rect
class Square : public Rect {
public:
    void display() override { cout << "Square "; }
};
int main() {
  vector<Shape*> V;
  V.push_back(new Rect);
  V.push_back(new Circle);
  V.push_back(new Square);
  V.push_back(new Circle);
  V.push_back(new Rect);
    // 使用多态显示形状
  for (int i = 0; i < V.size(); ++i) {
        V[i]->display();
    }
 cout << endl; // 输出: Rect Circle Square Circle Rect
   //使用 for_each 和 mem_fun 显示形状
 for_each(V.begin(), V.end(), mem_fun(&Shape::display));
cout << endl; // 输出: Rect Circle Square Circle Rect
    // 释放动态分配的内存
    for (auto* shape : V) {
        delete shape;
    }
    return 0;
}

语法层面不能写:for_each(V.begin(),V.end(),CShape::display);

也不能写:for_each(V.begin(),V.end(),Shape::display);

一定要以配接器 mem_fun 修饰 member function,才能被算法for_each 接受。

cpp 复制代码
#include <functional> // 为了使用 unary_function 和 binary_function
// "无任何参数"、"通过 pointer 调用"、"non-const 成员函数"
template <class S, class T>
class mem_fun_t : public std::unary_function<T*, S> {
public:
    explicit mem_fun_t(S (T::*pf)()) : f(pf) {} // 记录下来
    S operator()(T* p) const { return (p->*f)(); } // 转调用
private:
    S (T::*f)(); // 内部成员,pointer to member function
};
//"无任何参数"、"通过 pointer 调用"、"const 成员函数"
template <class S, class T>
class const_mem_fun_t : public std::unary_function<const T*, S> {
public:
    explicit const_mem_fun_t(S (T::*pf)() const) : f(pf) {}
    S operator()(const T* p) const { return (p->*f)(); }
private:
    S (T::*f)() const; // 内部成员,pointer to const member function
};
//"无任何参数"、"通过 reference 调用"、"non-const 成员函数"
template <class S, class T>
class mem_fun_ref_t : public std::unary_function<T, S> {
public:
    explicit mem_fun_ref_t(S (T::*pf)()) : f(pf) {} // 记录下来
    S operator()(T& r) const { return (r.*f)(); } // 转调用
private:
    S (T::*f)(); // 内部成员,pointer to member function
};
//"无任何参数"、"通过 reference 调用"、"const 成员函数"
template <class S, class T>
class const_mem_fun_ref_t : public std::unary_function<T, S> {
public:
    explicit const_mem_fun_ref_t(S (T::*pf)() const) : f(pf) {}
    S operator()(const T& r) const { return (r.*f)(); }
private:
    S (T::*f)() const; // 内部成员,pointer to const member function
};
//"有一个参数"、"通过 pointer 调用"、"non-const 成员函数"
template <class S, class T, class A>
class mem_fun1_t : public std::binary_function<T*, A, S> {
public:
    explicit mem_fun1_t(S (T::*pf)(A)) : f(pf) {} // 记录下来
    S operator()(T* p, A x) const { return (p->*f)(x); } // 转调用
private:
    S (T::*f)(A); // 内部成员,pointer to member function
};
//"有一个参数"、"通过 pointer 调用"、"const 成员函数"
template <class S, class T, class A>
class const_mem_fun1_t : public std::binary_function<const T*, A, S> {
public:
    explicit const_mem_fun1_t(S (T::*pf)(A) const) : f(pf) {}
    S operator()(const T* p, A x) const { return (p->*f)(x); }
private:
    S (T::*f)(A) const; // 内部成员,pointer to const member function
};
//"有一个参数"、"通过 reference 调用"、"non-const 成员函数"
template <class S, class T, class A>
class mem_fun1_ref_t : public std::binary_function<T, A, S> {
public:
    explicit mem_fun1_ref_t(S (T::*pf)(A)) : f(pf) {} // 记录下来
    S operator()(T& r, A x) const { return (r.*f)(x); } // 转调用
private:
    S (T::*f)(A); // 内部成员,pointer to member function
};
//"有一个参数"、"通过 reference 调用"、"const 成员函数"
template <class S, class T, class A>
class const_mem_fun1_ref_t : public std::binary_function<T, A, S> {
public:
    explicit const_mem_fun1_ref_t(S (T::*pf)(A) const) : f(pf) {}
    S operator()(const T& r, A x) const { return (r.*f)(x); }
private:
    S (T::*f)(A) const; // 内部成员,pointer to const member function
};
//mem_fun adapter 的辅助函数:mem_fun, mem_fun_ref
template <class S, class T>
inline mem_fun_t<S, T> mem_fun(S (T::*f)()) {
    return mem_fun_t<S, T>(f);
}
template <class S, class T>
inline const_mem_fun_t<S, T> mem_fun(S (T::*f)() const) {
    return const_mem_fun_t<S, T>(f);
}
template <class S, class T>
inline mem_fun_ref_t<S, T> mem_fun_ref(S (T::*f)()) {
    return mem_fun_ref_t<S, T>(f);
}
template <class S, class T>
inline const_mem_fun_ref_t<S, T> mem_fun_ref(S (T::*f)() const) {
    return const_mem_fun_ref_t<S, T>(f);
}
//具有一个参数的 mem_fun 和 mem_fun_ref 辅助函数
template <class S, class T, class A>
inline mem_fun1_t<S, T, A> mem_fun(S (T::*f)(A)) {
    return mem_fun1_t<S, T, A>(f);
}
template <class S, class T, class A>
inline const_mem_fun1_t<S, T, A> mem_fun(S (T::*f)(A) const) {
    return const_mem_fun1_t<S, T, A>(f);
}
template <class S, class T, class A>
inline mem_fun1_ref_t<S, T, A> mem_fun_ref(S (T::*f)(A)) {
    return mem_fun1_ref_t<S, T, A>(f);
}
template <class S, class T, class A>
inline const_mem_fun1_ref_t<S, T, A> mem_fun_ref(S (T::*f)(A) const) {
    return const_mem_fun1_ref_t<S, T, A>(f);
}
相关推荐
唐诺1 小时前
几种广泛使用的 C++ 编译器
c++·编译器
冷眼看人间恩怨2 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
红龙创客2 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin2 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
yuanbenshidiaos4 小时前
c++---------数据类型
java·jvm·c++
十年一梦实验室4 小时前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵
taoyong0014 小时前
代码随想录算法训练营第十一天-239.滑动窗口最大值
c++·算法
这是我585 小时前
C++打小怪游戏
c++·其他·游戏·visual studio·小怪·大型·怪物
fpcc5 小时前
跟我学c++中级篇——C++中的缓存利用
c++·缓存
呆萌很5 小时前
C++ 集合 list 使用
c++