author:
- luixiao1223
title: 使用traits classes表现类型信息
工具性templates
advance,可以将迭代器移动某个距离.
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d); // 如果d<0则可以向后移动.
STL的迭代器分类
一次一步,只能读取(写入)一次
istream_iterators
ostream_iterators
forward 迭代器
每次移动一个位置,但是可以读取多次.STL没有这种,有的实现了单链表的slist
bidirectional
可以向前向后移动一个位置,可以读取多次.set,multiset,map,multimap,list
random access
可以进行迭代算术,可以一次性移动多个距离.vector,deque,string.
如何实现advance
这是伪代码的实现思路
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{
if (iter is a random access iterator) {
iter += d;
}
else {
if (d >= 0) { while (d--) ++iter; }
else { while (d++) --iter; }
}
}
如何判断类的所属类型?实际上STL中有tag信息.可以使用tag信息
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<typename IterT>
struct iterator_traits;
template <...>
class deque {
public:
class iterator {
public:
typedef random_access_iterator_tag iterator_category;
};
};
template < ... >
class list {
public:
class iterator {
public:
typedef bidirectional_iterator_tag iterator_category;
};
};
// 标准库中的类型可以使用
template<typename IterT>
struct iterator_traits {
typedef typename IterT::iterator_category iterator_category; //获取内类型中的tag类型
};
// 用户自定义类型可以使用
template<typename T>
struct iterator_traits<T*>
{
typedef random_access_iterator_tag iterator_category; // 把指针的tag类型设置为random access
};
来实现advance看看
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{
if (typeid(typename std::iterator_traits<IterT>::iterator_category) ==
typeid(std::random_access_iterator_tag))
...;
}
有编译的问题.
typeid时发生在运行期.而其他的事情时可以在编译期完成的.所以这样的设计本身就浪费了.如何提前到编译期来?
函数重载
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d,
std::random_access_iterator_tag)
{
iter += d;
}
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d,
std::bidirectional_iterator_tag)
{
if (d >= 0) { while (d--) ++iter; }
else { while (d++) --iter; }
}
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d,
std::input_iterator_tag)
{
if (d < 0 ) {
throw std::out_of_range("Negative distance");
}
while (d--) ++iter;
}
这样,如果我们在此这样调用
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{
doAdvance(
iter, d,
typename
std::iterator_traits<IterT>::iterator_category()
);
}
这样就可以顺利的利用重载函数在编译期就确定要运行的时循环++还是直接+d.
TR1
这里面有很多关于traits的相关功能如
is_fundamental<T>, is_array<T>,is_base_of<T1,T2>
等等