STL源码剖析--侯捷
- 总结
尽管现在的很多语言支持参数类型的判别,但是c/c++并不支持这一特性。
但是我们可以通过一些技巧使得c++具有自动判别参数类型的特性。
- 模板
我们都知道在模板类和模板函数中我们不用具体指定参数的型别,编译器会自动的判别参数的类型。
所以我们想可不可以把编译器运行时所确定的型别萃取出来呢?
可以通过内嵌型别实现。
#include <iostream>
using namespace std; template <class T>
struct MyIter{
typedef T value_type;
//声明内嵌型别为value_type
T* ptr;
MyIter(T* p = ):ptr(p){ }
T& operator*()const{ return *ptr; }
}; template <class I>
typename I::value_type
//上面这一行告诉编译器这个型别,不然func无法返回
func(I ite)
{ return *ite; } int main(int argc, const char *argv[])
{
MyIter<int> ite(new int());
cout << func(ite) << endl;
//
return ;
}
~
这里的func函数就可以成功的把value_type萃取出来。
但是这里还有一个隐蔽的陷阱。
就是当我们这个迭代器是一个原生的指针时就会有问题,因为原生的指针并没有内嵌型别。
这就需要这个模板针对这个类型写一个偏特化的版本。
#include <iostream>
using namespace std; template <class T>
struct MyIter{
typedef T value_type;
//声明内嵌型别为value_type
T* ptr;
MyIter(T* p = ):ptr(p){ }
T& operator*()const{ return *ptr; }
}; template <class I>
struct iterator_traits_1{
typedef typename I::value_type value_type;
};
//对MyIter进行封装,获取它的内嵌型别 template <class T>
struct iterator_traits_1<T*>{
typedef T value_type;
};
//对原生指针进行型别的定义 template <class I>
typename iterator_traits_1<I>::value_type
//告诉编译器下面函数返回的型别
func(I ite)
{ return *ite; } int main(int argc, const char *argv[])
{
MyIter<int> ite(new int());
cout << func(ite) << endl;
//返回8
int a = ;
int *b = &a;
cout << func(b) << endl;
//返回5
return ;
}
这里我们对原来的类型MyIter又多了一层封装,这样的好处呢就是可以让下面的函数对原生指针也可以使用。
为了可以使用原生指针,我们又写了一个偏特化的版本。
特化版本和偏特化的版本的区别是,特化版本只是针对某一特定的类型实现。
而偏特化版本是对于一组特定的类型特化,更具一般性。
这里我们是针对所有的原生指针生成一个偏特化版本。
- 关于traits
traits在这里的作用是非常重要的,它所扮演的角色不仅仅是对各个类型的兼容,而且也是一个“类型萃取机”。
需要说明的一点就是要想兼容traits,必须有相关的内嵌型别定义;这一点在STL的迭代器中至关重要。
- iterator部分源码重列
//STL全部迭代器类型
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 {}; template <class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&>
struct iterator{
typedef Category iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
}; //类型萃取机traits
template <class Iterator>
struct iterator_traits{
typedef typename Iterator::iterator_category iterator_category;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::difference_type defference_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
}; //针对原生指针的偏特化版本
template <class T>
struct iterator_traits<T*>{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
}; //这个函数可以很方便的决定某个迭代器的类型(category)
template <class Iterator>
inline typename iterator_traits<Iterator>::iterator_category
iterator_category(const Iterator&)
{
typedef typename iterator_traits<Iterator>::iterator_category category;
return category();
} //这个函数可以很方便的决定某个迭代器的distance_type
template <class Iterator>
inline typename iterator_traits<Iterator>::difference_type*
distance_type(const Iterator&)
{
return static_cast<typename iterator_traits<Iterator>::difference_type*>();
} //这个函数可以很方便的决定某个迭代器的value_type
template <class Iterator>
inline typename iterator_traits<Iterator>::value_type*
value_type(const Iterator&)
{
return static_cast<typename iterator_traits<Iterator>::value_type*>();
} //以下是整组的distance函数
//两个__distance函数中的第三个参数没有实际意义,仅仅是为了判别迭
//代器类型
template <class InputIterator>
inline iterator_traits<InputIterator>::difference_type
__distance(InputIterator first, InputIterator last, input_iterator_tag){
iterator_traits<InputIterator>::difference_type n = ;
while(frist != last){
++first; ++n;
}
return n;
}
template <class RandomAccessIterator>
inline iterator_traits<RandomAccessIterator>::difference_type
__distance(RandomAccessIterator first, RandomAccessIteratorIterator last,
random_access_iterator_tag){
return last - first;
} template <class InputIterator>
inline iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last)
{
typedef typename
iterator_traits<InputIterator>::iterator_category category;
return __distance(first, last, category());
}
关于这些特性,在STL大量的使用,一定程度上补充了c++的不足;
最重要的是这些特性帮助我们在程序编译时就完成了类型的判断,而不是自己写个函数在运行时判断,这样做
更快,更高效。