先看下面是一个例子:
template
void func_impl(I iter, T t)
{
// ...
}
template
inline void func(I iter)
{
func_impl(iter, *iter);
// ...
}
int main()
{
int i;
func(&i);
return 0;
}
这里利用了function template的参数推导机制。“template参数推导技术”只是推出参数,无法推导返回值,怎么办?我们可以在迭代器里内嵌一个型别声明。如下:
template
struct MyIter
{
typedef T value_type;
// ....
};
template
typename I::value_type func(T iter)
{
return *iter;
}
通过在迭代器类里面嵌入一个声明,解决了推导返回值的问题(注意:上面要用typename,因为MyIter是个模板,编译器对T模板参数一无所知)!但问题又来了,并不是所有类型(如int *)都是calss type,所以无法为它定义内嵌型别,template partial specialization(模板偏特化)可以做到,但要用另一个模板作为中间层进而偏特化(这里就是__iterator_traits技法了),如下:
//__iterator_traits
template
struct iterator_traits
{
typedef typename I::value_type value_type;
};
//__iterator_traits偏特化版本,准确接受内置指针类型
template
struct iterator_traits
{
typedef T value_type;
};
//接受指向const类型数据的指针
template
struct iterator_traits
{
typedef T value_type;
};
所以,STL里的算法模板都是这样实现,如果我们要设计与STL水乳交融的类,那就要符合STL的一些基本要求了。STL中有5种迭代器,为了激活重载机制,定义的5个类型。每种迭代器就是一个类型。
struct input_iterator_tag{};
struct output_iterator_tag{};
struct forward_iterator_tag : public input_iterator_tag{};
struct bidirectional_iterator_tag:public forward_iterator_tag{};
struct random_access_iterator_tag:public bidirectional_iterator_tag{};
Iuput iterator,只读Random Access iterator,前四种提供基本操作(operator++,第四种在加上operator--),这种包含所有指针算术能力(p+n,p-n,p[n],p1
为了定义自己的迭代器,可以继承自下面的iterator类,避免迭代器型别的未定义。
//Base class for iterator class
template
struct iterator
{
typedef Category iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
};
iterator_traits类,就是一些typedef,相当于就是将迭代器的最本质的类型忠实的呈现出来。这里值得注意的是,要使得这个迭代器忠实的完成这项工作,那么各个迭代器的定义就必须定义相应的5个性别。value_type、 difference_type、 iterator_category、pointer、 reference .
template
struct iterator_traits
{
typedef typename Iterator::category iterator_category;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::difference_type difference_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
};
于是针对指针,我们定义了iterator_traits的特化版本。
template
struct iterator_traits
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T & reference;
};
template
struct iterator_traits
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T & reference;
};
下面的函数则是直接返回各个型别的类型:
template
inline typename iterator_traits::iterator_category
iterator_category(const Iterator&)
{
typedef typename iterator_traits::iterator_category category;
return category(); //random_access_iterator_tag or bidirectional_iterator_tag ...
}
//pointer to the difference_type
template< class Iterator>
inline typename iterator_traits::difference_type*
distance_type (const Iterator &)
{
return static_cast::difference_type *>(0);
}
template< class Iterator>
inline typename iterator_traits::value_type *
value_type (const Iterator &)
{
return static_cast::value_type* > (0);
}
distance函数在上述traits下的实现代码:
//distance function
template
inline iterator_traits::difference_type
__distance(InputIterator first, InputIterator last, input_iterator_tag)
{
iterator_traits::difference_type n=0;
while(first != last)
{
++first;++n;
}
return n;
}
template
inline typename iterator_traits::difference_type
__distance(RandomIterator first, RandomIterator last, random_access_iterator_tag)
{
return last-first;
}
//user
template
inline iterator_traits::difference_type
distance(InputIterator first, InputIterator last)
{
typedef typename iterator_traits::iterator_category category;
return __distance(first,last,category());//category()构造一个临时对象,进行参数推导,决定重载函数。
}
以下是advance
template
inline void __advance(InputIterator &i, Distance n, input_iterator_tag)
{
while (n--)++i;
}
template
inline void __advance(ForwardIterator &i, Distance n, forward_iterator_tag)
{
__advance(i, n, input_iterator_tag());
}
template
inline void __advance(BidirectionIterator &i, Distance n, bidirectional_iterator_tag)
{
if (n >= 0)
while(n--) ++i;
else
while(n++) --i;
}
template
inline void __advance(RandomAccessIterator &i, Distance n, random_access_iterator_tag)
{
i += n;
}
template
inline void advance(Iterator &i, Distance n)
{
__advance(i, n, iterator_traits::iterator_category());
}
来源:STL源码剖析