从零开始学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()函数
// 这是一个迭代器配接器,用来将某个迭代器的赋值操作改为插入操作,改为从容器的尾端插入
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()函数
//一个迭代器配接器,用来将某个迭代器的赋值操作改为插入操作——改为从容器的头部插入
//注意,该容器不支持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; }
};
//这是一个辅助函数,方便我们使用front_insert_iterator
template<class Container>
inline front_insert_iterator<Container> front_inserter(Container& x){
return front_insert_iterator<Container>(x);
}
insert_iterator类、inserter()函数
//这是一个迭代器配接器,用来将某个迭代器的赋值操作改为插入操作——在任意位置上插入
//并将迭代器右移一个位置——如此便可以方便地连续插入
//表面上是赋值操作,实际上是插入操作
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算法接受的不是一般的迭代器,而是这种逆向迭代器,它就会从尾到头的方向来处理序列中的元素。
使用迭代器模式理解这个过程:
//迭代器配接器,用来将某个迭代器逆反前进方向
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::cin
、std::cout
、文件流等)适配成符合标准迭代器接口的对象,使这些流可以与 C++ 标准库算法无缝地协同工作。
(1)绑定istream对象(如cin)的迭代器称为istream_iterator,istream_iterator将输入流适配成一个输入迭代器,使其可以像普通的迭代器一样通过递增操作(++
)读取数据并通过解引用(*
)访问当前值。
(2)绑定ostream(如cout)的迭代器称为ostream_iterator,将输出流适配成一个输出迭代器,使其可以像普通的输出迭代器一样通过赋值操作将数据写入流中,这些迭代器将它们对应的流当做一个特定类型的元素序列来处理。
istream_iterator
源码简化
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对象时必须使用输入流对象初始化它。当然也可以默认初始化迭代器,这样创建一个可以当做尾后值使用的迭代器。
#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进行构造。
//阻塞在此处,从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为初始值,此算法将迭代器所指的范围内的元素与初始值加在一起返回总和。
//阻塞在此处,从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
源码简化
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的尾后迭代器,因此不允许有默认初始化。
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的元素拷贝进输出流迭代器对象中进行输出。
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;
三种迭代器的综合使用:
#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;
}
函数适配器
函数适配器能够将仿函数和另一个仿函数(或某个值或某个一般函数)结合起来。
// 计算奇数元素的个数 这里的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
// 以下配接器用来表示某个 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
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
// 已知两个 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
用来将一个二元函数和两个一元函数组合成一个新的函数。这个新的函数首先分别应用两个一元函数(op2
和 op3
),然后将它们的结果作为参数传递给二元函数(op1
)。这样,新函数 h(x)
的行为是 h(x) = f(g1(x), g2(x))
。
用于函数指针:ptr_fun
函数指针不能直接传入STL算法的参数,需要使用函数适配器把他包装成仿函数使用。
#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
// 基类 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 接受。
#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);
}