条款47:请使用 traits classes 表现类型信息
Use traits classes for information about types.
STL 的 5 种迭代器分类
Input 迭代器:只能向前移动,一次一步,客户只可读取它们所指的东西,而且只能读取一次;
Output 迭代器:只能向前移动,一次一步,客户只可涂写它们所指的东西,而且只能涂写一次;
Forward 迭代器:可以做前两个迭代器的操作,而且可以读或写其所指物一次以上;
Bidirectional 迭代器:除了可以向前移动,还可以向后移动;
Random access 迭代器:可以在常量时间内向前或向后移动任意距离;
traits
traits 允许你在编译期间获取某些类型信息,例如 iterator_traits
,它的运作方式是针对每一个类型 IterT
,在 structure iterator_traits<IterT>
内一定声明某个 typedef 名为 iterator_category
的东西。
template<...>
class deque {
public:
class iterator {
public:
typedef random_access_iterator_tag iterator_category;
...
};
...
};
template<typename IterT>
class iterator_traits {
typedef typename IterT::iterator_category iterator_category;
...
};
为了支持指针迭代器,iterator_traits
特别针对指针提供一个偏特化版本(partial template specialization):
template<typename IterT>
struct iterator_traits<IterT*> {
typedef random_access_iterator_tag iterator_category;
...
};
而在实际使用过程中,可以通过 traits
在编译期间获取类型信息:
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)) {
...
}
}
不过这种使用方式存在问题,因为 IterT
类型在编译期间获知,所以 iterator_category
也可以在编译期间确定,但 if 语句却在运行期才会核定。这样不仅浪费时间,也造成可执行文件的膨胀。
如何使用 traits class
建立一组重载函数或函数模板,彼此间的差异只在于各自的 traits 参数;
建立一个控制函数或函数模板,它调用上述那些劳工函数并传递 traits class 所提供的信息;
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d),
std::random_access_iterator_tag) { // 用于 random access 迭代器;
iter += d;
}
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d),
std::bidirectional_iterator_tag) { // 用于 bidirectional 迭代器;
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) { // 用于 input 迭代器;
if (d < 0) {
throw std::out_of_range("Negative distance");
} else { while (d--) ++iter; }
}
template<typename IterT, typename DistT>
void advance(Iter& iter, DistT d) {
doAdvance(
iter, d,
typename
std::iterator_traits<IterT>::iterator_category()
);
}
Last updated
Was this helpful?