一、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;
}
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;
}
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不符,程序執行到某一步就會出錯;
二、標準庫算法的形式
template<class InputIterator,class Function>
Function for_each(InputIterator first,InputIterator last,Function f)
{
for(;first != last; ++first;)
{
f(*first);
}
return f;
}
4.算法count,count_if
array,vector,list,forward_list,deque
set/multiset
map/multiset
unordered_set/unordered_multiset
unordered_map/unordered_multimap
容器不帶成員函數find()
array,vector,list,forward_list,deque
set/multiset
map/multiset
unordered_set/unordered_multiset
unordered_map/unordered_multimap
容器不帶成員函數sort()
array,vector,deque
set/multiset
map/multiset
unordered_set/unordered_multiset
unordered_map/unordered_multimap
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
{
}myobj;
struct greater:public binary_function<T,T,bool>
bool operator()(const T&x,const T& y)const
{
return x>y;
}
/***************************************************************/
一個仿函數如果能夠適配適配器,它要能回答問題,怎樣才能回答問題呢?它需要繼承下面的兩個類;
爲了在其他地方搭配算法,就需要自己寫仿函數。
如果自己創建的仿函數沒有繼承適當的下面兩個之一,比如說上面代碼的前兩個sort,雖然可以運行,但是沒有很大的使用空間,它們不能適用於更加複雜的情況;
template<class Arg,class Result>
struct unary_function
{
typedef Arg argument_type;
typedef Result result_type;
}
struct binary_function
{
typedef Arg first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
}
/***************************************************************/
四、存在多種adapters
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)));
/***************************************************************/
bind2nd需要記下less 與40,然後進行操作;注意less不是一個操作;
//下面的代碼中,主要流程是這樣的:首先語句: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爲第二實參 }
}
//編譯器會自動推導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));
}
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)));
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);
}
};
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地址
template<class Iterator>
class reverse_iterator
{
protected:
Iterator current; //正向迭代器
}
//這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;
}
}
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));
}
/***************************************************************/
/***************************************************************/
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;}
}
/***************************************************************/