容器适配器:stack,queue
stack和queue内含一个deque
函数适配器
binder2nd绑定第二参数
- 调用的过程中,算法count_if函数读取了迭代器头尾指针后,读取第三个参数为functor
object即仿函数。因此在其参数为bind2nd(less< int>(),40)时首先要为bind2nd类构造一个对象。 - 在模板类bind2nd中传入的op为Operation泛型类型,编译器可在传入实参时自动推导Operation类型,并在后面返回调用构造binder2nd对象时用推导出的Operation类型构造binder2nd对象。
- 调用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作为返回类型。
- 回到count_if函数调用时,对第三个参数即仿函数对象调用
pred(*first);
,此时构造函数已经返回binder2nd对象,实质上是用重载()调用刚刚构造好的binder2nd对象,并return回Operation functor的调用,即less<int>(*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()是完全相同的,但是指向的元素一个在前一个在后。以下是逆向迭代器的源码,从运算符重载函数可以看出以上两个行为的体现:
inserter
我们知道标准库的copy()函数格式为:copy( begin(), end(), result() )
,将会在目的端进行元素的拷贝赋值,那么如果我们想在目的端做插入赋值该怎么办?答案是使用inserter(),所以copy()函数就可以写成这样:copy( begin(), end(), inserter(container, result()) )
可以看到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
观察构造函数看到,ostream_iterator接收一个basic_ostream和一个分隔符,通过对operator=的重载,将赋值运算符定义为往basic_ostream里面放东西,以此达到输出值的效果。
注意:operator * (),operator++(),operator++(int)什么都不做,只是return *this;
,和传统迭代器不同
istream_iterator
可以看到istream_iterator是通过重载operator++()来输入元素的,且在创建一个istream_iterator对象时,就会自动调用operator++(),等待一个数值的输入。若创建一个无参数的istream_iterator,其内部指针in_stream会被置为0,用来标志输入结束。
下面是一个copy函数调用istream_iterator的例子
在第一次创建istream_iterator对象时,已经输入了一个数值在对象的value成员中,调用*返回value成员,进行对inserter()函数返回的对象赋值,后面将inserter()对象++后再讲istream_iterator++,输入第二个数值,在下一轮赋给inserter()对象。