STL适配器-第四周学习笔记

template<class IputerIterator>
一、iterator_category对算法的影响
我们可以看到,代码3执行的时候会根据iterator_category的值选择1或者2,算法内部所做的操作是不一样的。算法的效率和它能不能判断出迭代器的类型有很大关系;
//..........................1...............................
template<class IputerIterator,class Distance>
inline void _advance(IputerIterator& i,Distance n,input_iterator_tag)
{
   while(n--);
   ++i;
}
//..........................2...................................
template<class BidirectionalIterator,class Distance>
inline void _advance(BidirectionIterater& i,Distance n,
                     bidirection_iterator_tag)
{
    if(n >= 0)
      while(n--) ++i;
    else
      while(n++) --i;
}
//..........................3...................................
template<class IputerIterator,class Distance>
inline void advance(IputerIterator& i,Distance n)
{
    _advance(i,n,iterater_category(i));
}

//.................................................................
template<class I>
inline typename iterator_traits<I>::iterator_category
iterator_traits(const I&)
{
      typedef typename iterator_traits<I>::iterator_category category;
      return category();
      //此函数协助取出iterator的category并以此创建一个临时对象
}

注:算法源码对iterator_category只是暗示,并非强制,如果算法与需要的iterator_category不符,程序执行到某一步就会出错;

二、标准库算法的形式
1.算法accumulate
2.算法for_each
template<class InputIterator,class Function>
Function for_each(InputIterator first,InputIterator last,Function f)
{
    for(;first != last; ++first;)
    {
        f(*first);
     }
     return f;
}
3.算法replace,replace_if,replace_copy
4.算法count,count_if
容器不带成员函数count()
array,vector,list,forward_list,deque
容器带有成员函数count()
set/multiset
map/multiset
unordered_set/unordered_multiset
unordered_map/unordered_multimap
算法find
容器不带成员函数find()
array,vector,list,forward_list,deque
容器带有成员函数find()
set/multiset
map/multiset
unordered_set/unordered_multiset
unordered_map/unordered_multimap
算法sort
容器不带成员函数sort()
array,vector,deque
set/multiset
map/multiset
unordered_set/unordered_multiset
unordered_map/unordered_multimap
容器带有成员函数find()
list,forward_list

三、仿函数
仿函数实际上是一个对象,如下面代码中的第三个和第四个sort的第三个参数都是类后面加小括号创建的一个临时对象;
/***************************************************************/
int arry[]={1,12,35,4,65,6,7,8,29,0};
vector myvec(arry,arry+10);
sort(myvec.begin(),myvec.end());  //默认比大小排序
sort(myvec.begin(),myvec.end(),myfun);  //use a functiom as comp
sort(myvec.begin(),myvec.end(),myobj);   //use object as comp
sort(myvec.begin(),myvec.end(),less<int>());  //use explicitly default comp
sort(myvec.begin(),myvec.end(),greater<int>());  //use another comp
struct myclass
{
   bool operator()(int i,int j){return (i<j); }
}myobj;
bool myfunc(int i,int j){ return (i< j); }
template<class T>
struct greater:public binary_function<T,T,bool>
  bool operator()(const T&x,const T& y)const
  {
      return x>y;
   }
/***************************************************************/
标准库提供的仿函数都有继承一个class,也就是下面两个类。继承这俩个类不会给子类增加额外的开销,因为它们没有data;
一个仿函数如果能够适配适配器,它要能回答问题,怎样才能回答问题呢?它需要继承下面的两个类;
为了在其他地方搭配算法,就需要自己写仿函数。
如果自己创建的仿函数没有继承适当的下面两个之一,比如说上面代码的前两个sort,虽然可以运行,但是没有很大的使用空间,它们不能适用于更加复杂的情况;
/***************************************************************/
template<class Arg,class Result>
struct unary_function
{
    typedef Arg argument_type;
    typedef Result result_type;
}
template<class Arg,class Arg2,class Result>
struct binary_function
{
   typedef Arg first_argument_type;
   typedef Arg2 second_argument_type;
   typedef Result result_type;
}
/***************************************************************/

四、存在多种adapters
适配器和它内含的对象之间是提问与回答的关系,问的问题是这几种,也就是前面提过的unary_function和binary_function
 typedef Arg first_argument_type;  //第一参数类型
 typedef Arg2 second_argument_type;  //第二参数类型
 typedef Result result_type;      //返回值类型

1.以函数适配器:binder2nd为例讲解适配器的使用
/***************************************************************/
cout << count_if(vi.bengin(),vi.end(),not1(bind2nd(less<int>(),40)));
/***************************************************************/
上面的代码中,count_if是算法,not1是函数适配器(negator),bind2nd是函数适配器,less是一个对象;
bind2nd需要记下less 与40,然后进行操作;注意less不是一个操作;
//以下将某个adaptable binary function转换为unary_function,只有这样才能回答算法的提问
//下面的代码中,主要流程是这样的:首先语句:bind2nd(less<int>(),40)) 是初始化一个bind2nd对象,在这里bind2nd将less对象与40绑定在一起;这里bind2nd并不是函数;
//随后,not1是取反,它的代码在下面,但它也是一个对象,not1(bind2nd(less<int>(),40))也是初始化一个not1对象;
//接着,count_if中执行的操作根据返回值判断是否计数;
/***************************************************************/
template<class Operator>
class binder2nd
  :public unary_function<typename Operator::first_argument_type,
                        typename Operator::result_type>
   //binder2nd本身是一个函数适配器,传给它的第一个参数即对象需要继承binary_function或unary_function
     种的一种以便回答binder2nd可能的提问,但是如果需要,binder2nd也需要继承回答一些自身的提问;
{
    protected:
      Operation op;  //内部成员,记录算式和第二实参
      typename Operation::second_argument_type value;
    public:
      //constructor
      binder2nd(const Operation& x,
                const typename Operator::second_argument_type& y)
             :op(x),value(y){} //记录算式和第二实参
    typename Operator::result_type
    operator()(const typename Operation::first_argument_type& x)const
    { return op(x,value); //实际呼叫算式并取value为第二实参 }
}
//辅助函数,让user得以方便使用binder2nd<op>;
//编译器会自动推导op的type,函数模板可以做实参推导
template<class Operation, class T>
inline binder2nd <Operation >bind2nd(const operator& op,const T&x)
{
   typedef typename Operation::second_argument_type arg2_type;
   return binder2nd<Operation>(op,arg_type(x));
}
template<class InputerIterator, class Predicate>
typename Iterator_traits<InputerIterator first,InputerIterator last,
                         Predicate pre>{
       typename iterator_traits<InputerIterator>::difference_type n= 0;
       for(;first != last; ++first)
       {
            if(pred(*first))  //如果元素带入pred的结果为true,
            ++n;
        }
        return n;
}
/***************************************************************/
/***************************************************************/
函数适配器:not1
cout << count_if(vi.bengin(),vi.end(),not1(bind2nd(less<int>(),40)));
//以下取某个Adapable Predicate的逻辑负值
template<class Predicate>
class unary_negate
   :public unary_function<typename Predicate::argument_type,bool>{
protected:
   Predicate pred;  //inner member
public:
   //constructor
   explicit unary_negate(const Predicate& x):pred(x){}
   bool operator()(const typename Predicate::argument_type& x)const{
   return !pred(x);
}
};
//辅助函数,使user得以方便使用unary_negate<Pred>
template<class Predicate>
inline unary_negate<Predicate>not1(const Predicate& pred){
   return unary_negate<Predicate>(pred);
}
/***************************************************************/

2.新型适配器 bind
std::bind可以绑定:
1.function
2.function object
3.member functions,_1必须是某个object地址
4.data member,_1必须是某个object地址
迭代器适配器reverse_iterator
template<class Iterator>
class reverse_iterator
{
   protected:
     Iterator current;  //正向迭代器
    
}
3.迭代器适配器inserter
/***************************************************************/
//这adapter将iterator的赋值(assign)操作改写为安插(insert)操作
//并将iterator右移一个位置,如此便可以让user连续执行表面上assign而实际上insert的行为
template<class Container>
class insert_iterator{
  protected:
     Container* container;
     typename Container::iterator iter;
  public:
     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);
       ++iter;
       return *this;
    }
}
//辅助函数,帮助使用者使用insert_iterator
template<class Container,class Iterator>
inline insert_iterator<Container>
inserter(Container& x,Iterator it){
   typedef typename Container::iterator iter;
   return insert_iterator<Container>(x,iter(it));
}
/***************************************************************/
X适配器:ostream_iterator  //x即未知
/***************************************************************/
template<class T,class char T = char,class traits = char_traits<charT>>
  class ostream_iterator:
    public iterator<output_iterator_tag,void,void,void,void>
  {
   protected:
      basic_ostream<charT,traits>* out_stream;
      const charT* delim;
  
   public:
      typedef charT char_type;
      typedef traits traits_type;
      typedef basic_ostream<charT,traits> ostram_type;
      ostream_iterator(ostream_type& s):out_stream(&s),delim(0){}
      ostream_iterator(ostream_type& s,const charT* delimiter)
          :out_stream(&s),delim(delimiter){}
      ostream_iterator(const ostream_iterator<T,charT,traits>& x)
          :out_stream(x.output_stream){}
      ~out_stream(){}
      ostream_iterator<T,charT,traits>& operator=(const& 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;}
   }
/***************************************************************/




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章