【c++从菜鸡到王者】第九篇:仿函数与适配器解析

仿函数

  1. 仿函数的用途主要是用来搭配STL算法,STL一般有两个版本,第一种表现出最常见的一种运算,第二种是由我们自己来规定如何运算,我们将以template参数来指定所要产生的运算,比如accumulate()其默认的行为是将元素相加,我们给其传入运算为相减的仿函数,取代第一版本的相加行为。
  2. 为了使仿函数可配接,所以必须继承基类unary_function或者binary_function.【使仿函数可配接,为了使算法更加的灵活】当继承了class,仿函数就获取了相应的型别,主要用来表现函数参数型别与返回值型别
template<class Arg, class Result>
struct unary_function {
    typedef Arg argument_type;			
    typedef Result result_type;			
};

template<class Argl, class Arg2, class Result>
struct binary_function {
    typedef Argl first_argument_type;	
    typedef Arg2 second_argument_type;	
    typedef Result result_type;			/
};
  1. 仿函数分为3类:算术类【支持加减乘除,模数和否定运算】。关系类【等于,大于,小于等等的二元运算】,逻辑类【AND,OR, NOT】,证同、选择、投射类【identity:任何数值通过该函数,都不会发生改变;select1st:接受pair,返回第一元素,select2nd:接受一个pair,返回第二元素;project1st,project2nd:传回第一参数,忽略第二参数,传回第二参数,忽略第一参数】

配接器

  1. 配接器有3类:容器配接器,仿函数配接器,迭代器配接器,分别改变容器接口,仿函数接口与迭代器接口
//容器配接器
//stack与queue都是deque的配接器
template<class T,class Sequence=deque<T>>
class stack{
    ...
    protected:
      Sequence c;
};
//queue同理,他们只使修饰dequ的接口

//仿函数适配器(not1,not2,bind1st,bind2st,compose1,compose2,ptr_fun,mem_fun,mem_fun_ref)
//对返回值进行否定的not1,not2,源代码如下:
template<class Predicate>
class unary_function:public unary_function<typename Predicate::argument_type,bool>{
    protected:pred;  //维护一个内部成员,记录仿函数的原始操作
    public:
       explicit unary_negate(const Predicate&x):pred(x){}
       bool operator()(const typename Predicate::argument_type&x)const{
           return !pred(x);//将pred的运算加上否定
       }
};
//创建辅助函数,使我们能够使用unary_negate<Pred>
template<class Predicate>
inline unary_negate<Predicate>not1(const Predicate&pred){
    return unary_negate<Predicate>(pred);
}
//class unary_function:public unary_function<typename Predicate::argument_type,bool>这个操作是为了使仿函数增强,可以在配接其他配置器,例如:
cout << count_if(vi.begin(),vi.end (),
                 not1(bind2nd(less<int>(), 40)));

//对参数进行绑定:bind1st,bind2st
template<class Operation>
class binderlst:public 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::first_argument_type&x)const{
        return op(value,x);//调用表达式,将value绑定为第一参数,我们传入的为第二参数
    }
};
//辅助函数
template<class Operation,class T>
inline binder1st<Operation>bind1st(const Operation,const T&x){
    typedef typename Operation::first_argument_type arg1_type;
    return binder1st<Operation>(op,arg1_type(x));
}
//用于函数合成的compose1,compose2
template<class Operation1,class operation2>
class unary_compose:public unary_function<typename Operation2::argument_type,typename Oeration1::result_type>{
    protected:
       Operation op1;
       Operation op2;
    public:
      unary_compose(const Operation1&x,conxt Operation2&y):op1(x),op2(y){}
    typename Operation1::resule_type
    operator()(const typename Operation2::argument_type&x)const{
        return op1(op2(x));
    }
};
template<class Operation1,class Operation2>
inline unary_compose<Operation1,Operation2>
compose1(const Operation1& op1,const Operation2& op2){
    return unary_compose<Operation2,Operation2>(op1,op2);
}
//用于函数指针的配接器可以将函数转化为仿函数
//用于成员函数的配接器可以将成员函数转化为仿函数
for_each(v.begon(),v.end(),mem_fun(&Shape::display));

//迭代器配接器:当客户端对insert iterators做复制操作的时候,在inserter iterators中转化为了插入操作// 适配器
template<class Container>
class insert_iterator {
protected:
    // 内部成员,记录底层容器和迭代器
    Container *container; 
    typename Container::iterator iter;
public:
    // 定义5个关联类型
    typedef output_iterator_tag iterator_category; 	
    
    insert_iterator(Container &x, typename Container::iterator i)
            : container(&x), iter(i) {}

    // 重载赋值运算符=
    insert_iterator<Container> &
	operator=(const typename Container::value_type &value) {
        iter = container->insert(iter, value); 		// 调用底层容器的insert
        ++iter; 									// 令insert_iterator永远随其target同步移动
        return *this;
    }
    
	// 重载运算符*和++: 不做任何动作
    insert_iterator<Container> &operator*() { return *this; }
    insert_iterator<Container> &operator++() { return *this; }
    insert_iterator<Container> &operator++(int) { return *this; }
};

// 辅助函数inserter
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));
}



//反转迭代器
template<class Iterator>
class reverse_iterator {
protected:
    Iterator current;			// 对应的正向迭代器
public:
	// 逆向迭代器的5种关联类型与正向迭代器相同
    typedef typename iterator_traits<Iterator>::itrator_category iterator_category;
    typedef typename iterator_traits<Iterator>::value_type value_type;
	// ...
    typedef Iterator iterator_type;				// 正向迭代器类型
    typedef reverse_iterator<Iterator> self;	// 逆向迭代器类型
public:
    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;return *this; }
    self &operator--() { ++current;return *this; }
    self operator+(difference_type n) const { return self(current - n); }
    self operator-(difference_type n) const { return self(current + n); }
};
//流迭代器
std::istream_iterator<double> eos; 				// 标志迭代器,通过与该迭代其比较以判断输入流是否终止
std::istream_iterator<double> iit(std::cin); 	// 封装std::cin的输入流迭代器

double value;
if (iit != eos) 
    value = *iit;		// 从输入流读取数据到变量value中,相当于: std::cin >> cvalue


template<class T, class charT=char, class traits=char_traits<charT>, class Distance=ptrdiff_t>
class istream_iterator :
        public iterator<input_iterator_tag, T, Distance, const T *, const T &> {
    basic_istream<charT, traits> *in_stream;	// 输入流
    T value;									// 上一次读入的值
public:
    typedef charT char_type;
    typedef traits traits_type;
    typedef basic_istream<charT, traits> istream_type;

    istream_iterator() : in_stream(0) {}							// 空迭代器,表示输入流终止
    istream_iterator(istream_type &s) : in_stream(&s) { ++*this; }	// 创建好迭代器后马上读入一个值 
    istream iterator(const istream_iterator<T, charT, traits, Distance> &x)
            : in_stream(x.in_stream), value(x.value) {}

    // 重载运算符++
    istream_iterator<T, charT, traits, Distance> &operator++() {
        if (in_stream && !(*in_stream >> value)) 
            in_stream = 0;
        return *this;
    }
	istream_iterator<T, charT, traits, Distance> operator++(int) {
        istream_iterator<T, charT, traits, Distance> tmp = *this;
        ++*this;
        return tmp;
    }
    
	// 重载运算符*和->
    const T &operator*() const { return value; }
    const T *operator->() const { return &value; }
};

代码参考(https://blog.csdn.net/ncepu_Chen/article/details/114947710)
书籍参考:stl源码剖析
c++系列文章:
【c++从菜鸡到王者】第八篇:深度剖析Traits技法
【c++从菜鸡到王者】第七篇:STL-空间配置器
【c++从菜鸡到王者】第六篇:详解晦涩难懂的c++语法
【c++从菜鸡到王者】第五篇-( 全网最精华)条件编译ifdef的用法
【c++从菜鸡到王者】第4篇:STL非标准容器-hashtable
【c++从菜鸡到王者】第三篇:STL关联容器-Map
【c++从菜鸡到王者】第二篇:STL关联容器-(multi)Set
【c++从菜鸡到王者】第一篇:STL之主要序列容器
如何使用好STL?这些经验你必须知道(进阶必备,建议收藏)!

上一篇:C++运算符重载


下一篇:C++ 类和对象 (运算符重载)