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;}
   }
/***************************************************************/




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