企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持知识库和私有化部署方案 广告
## 条款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`的东西。 ```cpp 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): ```cpp template<typename IterT> struct iterator_traits<IterT*> { typedef random_access_iterator_tag iterator_category; ... }; ``` 而在实际使用过程中,可以通过 `traits` 在编译期间获取类型信息: ```cpp 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 所提供的信息; ```cpp 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() ); } ```