使用traits技术表现迭代器类型 iterator_category
1.STL的迭代器類型標識,和容器中的迭代器類型。
2.使用trait技術實現stl的advance功能。
3.迭代器trait中的其他類型定義。?
?
1.STL的迭代器類型標識,和容器中的迭代器類型。
?熟悉的迭代器類型,輸入、輸出、前向、雙向、隨機。
c++標準程序庫分別提供專屬的卷標結構(tag struct),一個空的結構體來標志具體是哪種類型迭代器。如下:
// ITERATOR STUFF (from <iterator>)// ITERATOR TAGS (from <iterator>) struct input_iterator_tag{ // identifying tag for input iterators };struct output_iterator_tag{ // identifying tag for output iterators };struct forward_iterator_tag: input_iterator_tag, output_iterator_tag{ // identifying tag for forward iterators 這些繼承關系有有效的IS-A };struct bidirectional_iterator_tag: forward_iterator_tag{ // identifying tag for bidirectional iterators };struct random_access_iterator_tag: bidirectional_iterator_tag{ // identifying tag for random-access iterators};而在每個容器中,就使用上述的tag struct標識自自身迭代器的類型,大概的思路是下面的樣子,但真正源碼實現復雜多。
// vector 容器 隨機迭代器。list 容器 雙向迭代器。template<...> class vector{ public: class iterator{ public: typedef random_access_iterator_tag iterator_category;
// 類型定義: vector<T>::iterator::iterator_category 就是 random_access_iterator_tag
// 即類型里面還有一個類型, 而這個類型僅僅是用來標識 這個類是屬于哪個類型的。 }; };template<...> class list{ public: class iterator{ public: typedef bidirectional_iterator_tag iterator_category; }; };
?
2.使用trait技術實現stl的advance功能。
STL標準模版庫={容器templates,迭代器templates(關聯容器 和 算法),算法templates,工具性template如advance}。這里選擇迭代器模版和Advance的實現來講解trait技術。
?
先看看advance的用法:
// advance 函數簽名std::advance template <class Iterator, class Distance>void advance (Iterator& it, Distance n); // advance example #include <iostream> // std::cout #include <iterator> // std::advance #include <list> // std::listint main () {std::list<int> mylist;for (int i=0; i<10; i++) mylist.push_back (i*10);std::list<int>::iterator it = mylist.begin();std::advance (it,5); std::cout << "The sixth element in mylist is: " << *it << '\n';return 0; }
advance內部操作時候,需要知道advance的迭代器類型,看有哪些可用操作,比如隨機訪問器可以直接+= -=操作,前向僅支持++,輸入輸出均不支持,例子中的list屬于雙向,支持++,--。
所以在advance內部需要在取得某種類型信息,即迭代器的類型,進行不同的實現。
?
如何取得類型信息呢,在1中其實我們已經定義了迭代器的類型,可以通過 ”容器類型::iterator::iterator_category“來獲取類型信息。
但如果要支持內置類型,比如指針是一種隨機迭代器類型,那么類型信息就不能放在類型內了,意味著類型內的嵌套類的方式不能工作,所以類型的信息必須位于類型自身之外。
?
trait標準技術是把它放進一個template,并進行一個偏特化版本,來實現迭代器所屬類型trait。trait特性的意思 就有有關迭代器的相關特性。
// 即再封裝一層,如果是用戶自定義的,就直接獲取內部定義的迭代器類型 // 如果是內置類型,就直接給設定成他所屬的迭代器類型,用模版偏特化 // iterator_traits template<typename IterT> struct iterator_traits{ typedef typename IterT::iterator_category iterator_category; // 注意: 這里typename關鍵字 指示編譯器解析 IterT::iterator_category 為一個類型 ... };template<typename IterT> //template 偏特化,針對內置指針 struct iterator_traits<IterT*>{ typedef random_access_iterator_tag iterator_category; };template<typename IterT> struct iterator_traits<const IterT*>{ typedef random_access_iterator_tag iterator_category; }; ?
?
在advance的用法中,就可以使用?iterator_traits 類來判斷是什么類型
// 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)) { iter += d;} else if(前向迭代器類型){ if (d < 0){throw std::out_of_range("Negative distance");} while (d--) ++iter; }else if(等等其他類型)... }
?
使用重載函數的機制,在編譯器就確定調用哪個迭代器類型的advance,以提高運行時效率。
// advance編譯器確定使用哪種迭代器類型版本 template<typename IterT, typename DistT> void advance(IterT& iter, DistT d) { doAdvance(iter, d, typename std::iterator_traits<IterT>::iterator_category()); } // 比如 雙向迭代器的函數 。重載doAdvance,實現不同的迭代器類型的具體操作。 // 可以看到迭代器類型僅僅是個重載的作用,使得重載機制得以運行,都不需要變量名。 void doAdvance(IterT& iter, DistT d, std::bidirectional_iterator_tag) { if (d >= 0) {while (d--) ++iter;} else {while(d++) --iter;} }?
3.迭代器trait中的其他類型定義
?
?
template<class IterT> struct iterator_traits{typedef typename IterT::iterator_category iterator_category; // 迭代器的類型所屬typedef typename IterT::value_type value_type; // 迭代器所指對象的類型typedef typename IterT::difference_type difference_type; // 迭代器之間的距離 typedef typename IterT::pointer pointer; // 迭代器所指內容的地址typedef typename IterT::reference reference; // 迭代器所指之內容 };template<typename IterT> //template 偏特化,針對內置指針 struct iterator_traits<IterT*>{ typedef random_access_iterator_tag iterator_category; typedef IterT value_type; typedef ptrdiff_t difference_type ;typedef IterT* pointer ; typedef IterT& reference ; };
?
?
另外,STL提供了一個 iterator類,如果每個新設計的迭代器都繼承他,可保證符合STL所需的規范。
// TEMPLATE CLASS iterator template<class _Category,class _Ty,class _Diff = ptrdiff_t,class _Pointer = _Ty *,class _Reference = _Ty&>struct iterator{ // base type for iterator classes typedef _Category iterator_category;typedef _Ty value_type;typedef _Diff difference_type;typedef _Pointer pointer;typedef _Reference reference;};?
?
?
整理自 effective C++ 條款 47:使用traits classes表現類型信息
轉載于:https://www.cnblogs.com/fulina/p/7058288.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的使用traits技术表现迭代器类型 iterator_category的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 济南遥墙机场停5天怎么收费,济南遥墙国际
- 下一篇: HALCON示例程序stamp_cata