zoukankan      html  css  js  c++  java
  • STL源码剖析(四)

    functors

    仿函数(functor),就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了。

    在STL中,将仿函数主要分为了三大类:算术类(Arithmetic)、逻辑运算类(Logical)和相对关系类(Relational)。

    算术类(Arithmetic)举例

    template <class T>
    struct plus : public binary_function<T, T, T>
    {
        T operator()(const T& x, const T& y) const
        { return x + y; }
    };
    
    template <class T>
    struct minus : public binary_function<T, T, T>
    {
        T operator()(const T& x, const T& y) const
        { return x - y; }
    };
    
    ...
    

    逻辑运算类(Logical)举例

    template <class T>
    struct logical_and : public binary_function<T, T, bool>
    {
        bool operator()(const T& x, const T& y) const
        { return x && y; }
    };
    
    ...
    

    相对关系类(Relational)

    template <class T>
    struct equal_to : public binary_function<T, T, bool>
    {
        bool operator()(const T& x, const T& y) const
        { return x == y; }
    };
    
    template <class T>
    struct less : public binary_function<T, T, bool>
    {
        bool operator()(const T& x, const T& y) const
        { return x < y; }
    };
    
    ...
    

    通过上面的代码可以发现,functors都继承了一个基类。STL规定每个 Adaptable Function 都应该挑选合适的父类继承,因为 Adaptable Function 将会提问一些问题。

    template <class Arg, class Result>
    struct unary_function
    {
        typedef Arg argument_type;
        typedef Result result_type;
    };
    
    template <class Arg1, class Arg2, class Result>
    struct binary_function
    {
        typedef Arg1 first_argument_type;
        typedef Arg2 second_argument_type;
        typedef Result result_type;
    };
    

    比如上面的less通过继承binary_function拥有了3个typedef,这些typedef可能会在一些适配器中被询问到,详见后面适配器中的源码。

    Adapters

    Adapters 相当于一种修饰的作用,在容器、迭代器和仿函数的基础上,对其进行一种改造。将改造完成后的容器、迭代器或仿函数交给用户使用,但其核心还是通过内部的容器、迭代器和仿函数进行工作。所以就存在: Container Adapters, Iterator Adapters 和 Functor Adapters三类。

    容器适配器:stack, queue

    stack

    template <class T, class Sequence=deque<T>>
    class stack{
    ...
    public:
        typedef typename Sequence::value_type value_type;
        typedef typename Sequence::size_type size_type;
        typedef typename Sequence::reference reference;
        typedef typename Sequence::const_reference const_reference;
    proctected:
        Sequence c;// 底层容器
    public:
        bool empty() const { return c.empty(); }
        size_type size() const { return c.size(); }
        reference top() { return c.back(); }
        const_reference top const { return c.back(); }
        void push(const value_type& x) { c.push_back(x); }
        void pop { c.pop_back(); }
    };
    

    queue

    template <class T, class Sequence=deque<T>>
    class queue{
    ...
    public:
        typedef typename Sequence::value_type value_type;
        typedef typename Sequence::size_type size_type;
        typedef typename Sequence::reference reference;
        typedef typename Sequence::const_reference const_reference;
    proctected:
        Sequence c;// 底层容器
    public:
        bool empty() const { return c.empty(); }
        size_type size() const { return c.size(); }
        reference front() { return c.front(); }
        const_reference front() const { return c.front(); }
        reference back() { return c.back(); }
        const_reference back() const { return c.bakc(); }
        void push(const value_tyoe& x) { c.push_back(x); }
        void pop { c.pop_back(); }
    };
    

    函数适配器:binder2nd, not1

    对于这样一行语句:

    cout << count_if(vi.begin(), vi.end(), not1(bind2nd(less<int>(), 40));

    首先需要注意的是less<int>()这并不是函数的调用,而是生成一个less<int>的对象!

    count_if

    template <class InputIterator, class Predicate>
    typename iterator_traits<InputIterator>::difference_type 
    count_if(InputIterator first, 
             InputIterator last, 
             Predicate pred){
        typename iterator_traits<InputIterator>::difference_type n = 0;
        for(; first != last; ++first)
            if(pred(*first))
                ++n;
        return n;
    }
    

    bind2nd

    template <class Operation, class T>
    inline binder2nd<Operation> bind2nd(const Operation& op,const T& x)
    {
        typedef typename Operator::second_argument_type arg2_type;
        return binder2nd<Operation>(op, arg2_type(x));//返回一个binder2nd<Operation>对象!
    }
    
    

    binder2nd

    template <class Operation>
    class binder2nd : public 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);//这里才是函数的调用
        }
    };
    

    在这些代码中可以看到适配器在询问仿函数一些问题,这些问题就是仿函数继承的基类中的typedef。所有能回答出这些问题的仿函数都称为 Adaptable Function

    not1

    template <class Predicate>
    inline unary_negate<Predicate> not1(consat Predicate& pred)
    {
        return unary_negate<Predicate>(pred);
    }
    
    template <class Predicate>
    class unary_negate : public unart_function<typename Predicate::argument_type, bool>
    {
    protected:
        Predicate pred;
    public:
        eplicit unary_negate(const Predicate& x) : pred(x) {}
        bool operator()(const typename Predicate::argument_type& x) const
        {
            return !pred(x);
        }
    };
    

    新型适配器,bind

    bind 使用例子(摘自cplusplus网站)

    #include <iostream>     // std::cout
    #include <functional>   // std::bind
    
    // a function: (also works with function object: std::divides<double> my_divide;)
    double my_divide (double x, double y) {return x/y;}
    
    struct MyPair {
      double a,b;
      double multiply() {return a*b;}
    };
    
    int main () {
      using namespace std::placeholders;    // adds visibility of _1, _2, _3,...
    
      // binding functions:
      auto fn_five = std::bind (my_divide,10,2);               // returns 10/2
      std::cout << fn_five() << '
    ';                          // 5
    
      auto fn_half = std::bind (my_divide,_1,2);               // returns x/2
      std::cout << fn_half(10) << '
    ';                        // 5
    
      auto fn_invert = std::bind (my_divide,_2,_1);            // returns y/x
      std::cout << fn_invert(10,2) << '
    ';                    // 0.2
    
      auto fn_rounding = std::bind<int> (my_divide,_1,_2);     // returns int(x/y)
      std::cout << fn_rounding(10,3) << '
    ';                  // 3
    
      MyPair ten_two {10,2};
    
      // binding members: member function 其实有个 argument: this
      auto bound_member_fn = std::bind (&MyPair::multiply,_1); // returns x.multiply()
      std::cout << bound_member_fn(ten_two) << '
    ';           // 20
    
      auto bound_member_data = std::bind (&MyPair::a,ten_two); // returns ten_two.a
      std::cout << bound_member_data() << '
    ';                // 10
    
      return 0;
    }
    

    std::bind 可以绑定:

    1. functions
    2. function objects
    3. member functions, _1 必须是某个object地址
    4. data members, _ 必须是某个object地址

    所以可以现在可以用bind替换bind2nd,改写如下:

    vector<int> v {15,37,94,50,73,58,28,98};
    int n = count_if(v.cbegin(), v.cend(), not1(bind2nd(less<int>, 50)));
    cout << "n=" << n << endl;//5
    
    vector<int> v {15,37,94,50,73,58,28,98};
    int n = count_if(v.cbegin(), v.cend(), not1(bind(less<int>, _1, 50)));
    cout << "n=" << n << endl;//5
    

    迭代器适配器 reverse_iterator, inserter

    reverse_iterator:用来实现去反向指针rbegin(), rend()的实现。

    reverse_iterator rbegin() { return reverse_iterator(end()); }
    
    reverse_iterator rend() { returun reverse_iterator(begin()); }
    
    template <class Iterator>
    class reverse_iterator
    {
    protected:
        Iterator current;//对应的正向迭代器
    public:
        //逆向迭代器的5中 associated types 都和对应的正向迭代器相同
        typedef typename iterator_traits<Iterator>::iterator_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; }
        slef operator+(difference_type n) const { return self(current - n); }
        slef operator-(difference_type n) const { return self(current + n); }
    };
    

    inserter: 将iteartor中的复制操作改为插入操作,并且将iteartor右移一个位子。可以让用户执行表面上assign而实际上insert的行为。

    template <class Container>
    class insert_iterator
    {
    protected:
        Container* container;
        typename Container::iterator iter;
    pbulic:
        typedef output_iterator_tag iterator_category;
        insert_iterator(Container& x, typename Container::iterator i) : container(&x), iter(i) {}
        //对赋值操作符重载,以实现插入
        insert_iterator<Contain>& operator=(const typename Container::value_type& value)
        {
            iter = container->insert(iter, value);
            ++iter;
            return *thisl
        }
    };
    
    //辅助函数,帮助用户使用insert_iterator
    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));
    }
    

    特殊适配器 ostream_iterator, istream_iterator

    ostream_iterator

    先来看一个例子

    #include <iostream>     //std::cout
    #include <iterator>     //std::ostream_iterator
    #include <vector>       //std::vector
    #include <algorithm>    //std::copy
    
    int main()
    {
    	std::vector<int> myvector;
    	for (int i = 1; i < 10; ++i) myvector.push_back(i * 10);
    
    	std::ostream_iterator<int> out_it(std::cout, ",");
    	std::copy(myvector.begin(), muvector.end(), out_it);
    	return 0;
    }
    
    

    输出结果:

    10,20,30,40,50,60,70,80,90,
    

    首先来看看copy这个函数做了什么

    template<class InputIterator first, InputIterator last,OutputIterator result>
    copy(InputIterator first,InputIterator last, OutputIterator result)
    {
        while(first != last)
        {
            *result = *first;
            ++result;
            ++first;
        }
    }
    

    再对比着ostream_iterator的源码,就能分析出输出的原因:

    template<class T,class chatT=char,class traits=char_traits<charT>>
    class ostream_iterator:public iterator<output_iterator_tag,void,void,void,void>
    {
        basic_ostream<charT,traits>* out_stream;
        const charT* delim;
    public:
        typedef charT char_type;
        typedef traits traits_type;
        typedef basic_ostream<charT,traits> ostream_type;
        ostream_iterator(ostream_type& s):out_stream(&s),delim(0){}
        ostream_iterator(onstream_type&s, const charT* delimiter):out_stream(&s),delim(delimiter){}
        ostream_iterator(const ostream_iterator<T,charT,traits>& x):ostream_iterator(x.out_stream),delim(x.delim){}
        ~ostream_iterator(){}
        ostream_iterator<T,chatT,traits>& operator=(const T& value){//关键点!!
            *out_stream << value;
            if(delim!=0) 
                *out_stream << delim;
            return *this;
        }
    
        ostream_iterator<T,charT,traits>& operator*(){return *this;}
        ostream_iterator<T,charT,traits>& operator++(){return *this;}
        ostream_iterator<T,charT,traits>& operator++(int){return *this;}
    };
    

    关键就在于重载了=号运算符。

    istream_iterator

    还是先看一个例子

    #include <iostream>
    #include <iterator>
    
    int main()
    {
    	double value1, value2;
    	std::cout << "Please, insert two values:";
    	std::istream_iterator<double> eos;
    	std::istream_iterator<double> iit(std::cin);//当创建对象时,就已经在要求输入了
    	if (iit != eos)
    		value1 = *iit;
    	++iit;
    	if (iit != eos)
    		value2 = *iit;
    	std::cout << value1 << "*" << value2 << "=" << (value1*value2) << "
    ";
    	return 0;
    }
    

    这个例子就是一个简单的乘法,其中std::istream_iterator<double> iit(std::cin);相当于cin >> value;。具体的原理还是看源码吧。

    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>* instream;
    	T value;
    public:
    	typedef charT char_type;
    	typedef traits traits_type;
    	typedef basic_istream<charT, traits> istream_type;
    	istream_iterator() :instream(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_itetator() {}
    	const T& operator*() const { return value; }
    	const T* operator->() const { return 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;
    	}
    };
    

    对照源码可以发现,std::istream_iterator<double> iit(std::cin);这里调用了istream_iterator的++符号,此时就已经开始输入了。

  • 相关阅读:
    [学习笔记] Symfony2学习笔记之数据库操作 [转]
    [学习笔记] Twig 的 tags学习 [转]
    [学习笔记] 设计模式之状态机模式 [转]
    【转】Lombok介绍、使用方法和总结
    RabbitMQ
    百度云下载不限速方法+软件
    json数据的key的读取和替换
    spring boot配置mybatis和事务管理
    windows强大的快捷键
    rtsp向rtmp推流
  • 原文地址:https://www.cnblogs.com/joker-wz/p/10299617.html
Copyright © 2011-2022 走看看