STL分析(九 适配器)

容器适配器:stack,queue

STL分析(九 适配器)_第1张图片
stack和queue内含一个deque

函数适配器

binder2nd绑定第二参数

STL分析(九 适配器)_第2张图片

  1. 调用的过程中,算法count_if函数读取了迭代器头尾指针后,读取第三个参数为functor
    object即仿函数。因此在其参数为bind2nd(less< int>(),40)时首先要为bind2nd类构造一个对象。
  2. 在模板类bind2nd中传入的op为Operation泛型类型,编译器可在传入实参时自动推导Operation类型,并在后面返回调用构造binder2nd对象时用推导出的Operation类型构造binder2nd对象。
  3. 调用binder2nd构造函数时将less< int>()临时对象交给op成员,绑定的第二个参数40交给value成员。binder2nd由于已经被绑定了一个操作数,因此继承unary_function,只有一个参数。在binder2nd中,内含了一个Operation类型functor和一个以该functor第二参数为类型的第二参数value。由于调用的函数对象less< int>()等一般有两个操作数,其继承自binary_function。由于后面这个binder2nd函数对象要调用()来调用内涵的Operation function,因此其需要重载()操作符,并以Operation function的result_type作为返回类型。
  4. 回到count_if函数调用时,对第三个参数即仿函数对象调用pred(*first);,此时构造函数已经返回binder2nd对象,实质上是用重载()调用刚刚构造好的binder2nd对象,并return回Operation functor的调用,即less(*first, value);

not1

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

在被上面的count_if()函数调用时,not1函数对象调用operator()返回里面的相反条件。

bind

在C++11后,bind1st,bind2nd等被bind取代。bind可以绑定四种东西(1)函数与仿函数(2)类的成员函数及数据成员,其中_1必须是某个object的地址
第一种:

double my_divide (double x, double y)
    { return x / y; }
 
//bind的使用示例
auto fn_five = bind(my_divide, 10, 2);               //fn_five() return 10/2
 
auto fn_half = bind(my_divide, _1, 2);               //fn_half(x) return x/2
 
auto fn_invert = bind(my_divide, _2, _1);            //fn_invert(x, y) return y/x
 
auto fn_rounding = bind<int> (my_divide, _1, _2);    //fn_rounding(x, y) return (int)x/y

其中_n为占位符,意思是实际调用第n个参数。如第三个例子_2为第二个参数y,_1位第一个参数x,在后面调用fn_invert(x, y)即可以实现参数互换

第二种:

struct MyPair{
    double a, b;
    double multiply() { return a * b; }
        //member function其实有个argument:this
};
 
 
//binding类的成员的示例
MyPair ten_two {10, 2};
 
auto bound_memfn = bind(&MyPair::multiply(), _1);
    //bound_memfn(x) return x.multiply()
 
auto bound_memdata = bind(&MyPair::a, ten_two);
    //bound_memdata() return tem_two.a
 
auto bound_memdata2 = bind(&MyPair::b, _1);
    //bound_memdata2(x) return x.b

可以看出bind可以实现绑定类的成员,无论是数据成员还是函数成员,bind需要传入成员指针,它的_1始终表示对象的this指针,当不指定具体传入的对象时,调用bind后的结果时就需要传入一个object,有点像一个隐藏参数。

迭代器适配器

reverse_iterator

以看出逆向迭代器需要满足两个行为:(1)正确地引用元素值。(2)方向和原来相反。以rbegin()为例,它的值按理来说和end()是完全相同的,但是指向的元素一个在前一个在后。以下是逆向迭代器的源码,从运算符重载函数可以看出以上两个行为的体现:

STL分析(九 适配器)_第3张图片

inserter

我们知道标准库的copy()函数格式为:copy( begin(), end(), result() ),将会在目的端进行元素的拷贝赋值,那么如果我们想在目的端做插入赋值该怎么办?答案是使用inserter(),所以copy()函数就可以写成这样:copy( begin(), end(), inserter(container, result()) )
STL分析(九 适配器)_第4张图片
可以看到inserter中也采用了用inserter主函数推导了模板实参Container和Container::iter
的类型后调用次函数insert_iterator。在次函数中实现了操作符=的重载,在调用*result = *first;时调用operator=()重载,对result迭代器指向的地方做insert()操作,再将insert_iterator同步到insert()返回的指针的后一位,即下一个target上。
注意:insert_iterator的重载的++运算符操作并不做任何事情,只是return *this,因此++iter;的操作必须在operator=()中实现,以移动target指针

ostream和istream的适配器

ostream_iterator

STL分析(九 适配器)_第5张图片
观察构造函数看到,ostream_iterator接收一个basic_ostream和一个分隔符,通过对operator=的重载,将赋值运算符定义为往basic_ostream里面放东西,以此达到输出值的效果。
注意:operator * (),operator++(),operator++(int)什么都不做,只是return *this;,和传统迭代器不同

istream_iterator

STL分析(九 适配器)_第6张图片
可以看到istream_iterator是通过重载operator++()来输入元素的,且在创建一个istream_iterator对象时,就会自动调用operator++(),等待一个数值的输入。若创建一个无参数的istream_iterator,其内部指针in_stream会被置为0,用来标志输入结束。

下面是一个copy函数调用istream_iterator的例子
STL分析(九 适配器)_第7张图片
在第一次创建istream_iterator对象时,已经输入了一个数值在对象的value成员中,调用*返回value成员,进行对inserter()函数返回的对象赋值,后面将inserter()对象++后再讲istream_iterator++,输入第二个数值,在下一轮赋给inserter()对象。

你可能感兴趣的:(C++基础学习,c++,javascript,算法)