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