程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++箴言: 教你為類型信息使用特征類的方法

C++箴言: 教你為類型信息使用特征類的方法

編輯:C++入門知識

STL 主要是由 containers(容器),iterators(迭代器)和 algorithms(算法)的 templates(模板)構成的,但是也有幾個 utility templates(實用模板)。其中一個被稱為 advance。advance 將一個指定的 iterator(迭代器)移動一個指定的距離:

template<typename IterT, typename DistT> // move iter d units
void advance(IterT& iter, DistT d); // forward; if d < 0,
// move iter backward
  在概念上,advance 僅僅是在做 iter += d,但是 advance 不能這樣實現,因為只有 random access iterators(隨機訪問迭代器)支持 += operation。不夠強力的 iterator(迭代器)類型不得不通過反復利用 ++ 或 -- d 次來實現 advance。

  你不記得 STL iterator categories(迭代器種類)了嗎?沒問題,我們這就做一個簡單回顧。 對應於它們所支持的操作,共有五種 iterators(迭代器)。input iterators(輸入迭代器)只能向前移動,每次只能移動一步,只能讀它們指向的東西,而且只能讀一次。它們以一個輸入文件中的 read pointer(讀指針)為原型;C++ 庫中的 istream_iterators 就是這一種類的典型代表。output iterators(輸出迭代器)與此類似,只不過用於輸出:它們只能向前移動,每次只能移動一步,只能寫它們指向的東西,而且只能寫一次。它們以一個輸出文件中的 write pointer(寫指針)為原型;ostream_iterators 是這一種類的典型代表。這是兩個最不強力的 iterator categories(迭代器種類)。因為 input(輸入)和 output iterators(輸出迭代器)只能向前移動而且只能讀或者寫它們指向的地方最多一次,它們只適合 one-pass 運算。

  一個更強力一些的 iterator category(迭代器種類)是 forward iterators(前向迭代器)。這種 iterators(迭代器)能做 input(輸入)和 output iterators(輸出迭代器)可以做到的每一件事情,再加上它們可以讀或者寫它們指向的東西一次以上。這就使得它們可用於 multi-pass 運算。STL 沒有提供 singly linked list(單向鏈表),但某些庫提供了(通常被稱為 slist),而這種 containers(容器)的 iterators(迭代器)就是 forward iterators(前向迭代器)。TR1 的 hashed containers(哈希容器)的 iterators(迭代器)也可以屬於 forward category(前向迭代器)。

  bidirectional iterators(雙向迭代器)為 forward iterators(前向迭代器)加上了和向前一樣的向後移動的能力。STL 的 list 的 iterators(迭代器)屬於這一種類,set,multiset,map 和 multimap 的 iterators(迭代器)也一樣。

  最強力的 iterator category(迭代器種類)是 random access iterators(隨機訪問迭代器)。這種 iterators(迭代器)為 bidirectional iterators(雙向迭代器)加上了 "iterator arithmetic"(“迭代器運算”)的能力,也就是說,在常量時間裡向前或者向後跳轉一個任意的距離。這樣的運算類似於指針運算,這並不會讓人感到驚訝,因為 random access iterators(隨機訪問迭代器)就是以 built-in pointers(內建指針)為原型的,而 built-in pointers(內建指針)可以和 random access iterators(隨機訪問迭代器)有同樣的行為。vector,deque 和 string 的 iterators(迭代器)是 random access iterators(隨機訪問迭代器)。

  對於五種 iterator categories(迭代器種類)中的每一種,C++ 都有一個用於識別它的 "tag struct"(“標簽結構體”)在標准庫中:

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 {};
  這些結構體之間的 inheritance relationships(繼承關系)是正當的 is-a 關系:所有的 forward iterators(前向迭代器)也是 input iterators(輸入迭代器),等等,這都是成立的。我們不久就會看到這個 inheritance(繼承)的功用。

  但是返回到 advance。對於不同的 iterator(迭代器)能力,實現 advance 的一個方法是使用反復增加或減少 iterator(迭代器)的循環的 lowest-common-denominator(最小共通特性)策略。然而,這個方法要花費 linear time(線性時間)。random access iterators(隨機訪問迭代器)支持 constant-time iterator arithmetic(常量時間迭代器運算),當它出現的時候我們最好能利用這種能力。

  我們真正想做的就是大致像這樣實現 advance:

template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{
 if (iter is a random access iterator) {
  iter += d; // use iterator arithmetic
 } // for random access iters
 else {
  if (d >= 0) { while (d--) ++iter; } // use iterative calls to
  else { while (d++) --iter; } // ++ or -- for other
 } // iterator categories
}
  這就需要能夠確定 iter 是否是一個 random access iterators(隨機訪問迭代器),依次下來,就需要知道它的類型,IterT,是否是一個 random access iterators(隨機訪問迭代器)類型。換句話說,我們需要得到關於一個類型的某些信息。這就是 traits 讓你做到的:它們允許你在編譯過程中得到關於一個類型的信息。 traits 不是 C++ 中的一個關鍵字或預定義結構;它們是一項技術和 C++ 程序員遵守的慣例。建立這項技術的要求之一是它在 built-in types(內建類型)上必須和在 user-defined types(用戶定義類型)上一樣有效。例如,如果 advance 被一個指針(譬如一個 const char*)和一個 int 調用,advance 必須有效,但是這就意味著 traits 技術必須適用於像指針這樣的 built-in types(內建類型)。

  traits 對 built-in types(內建類型)必須有效的事實意味著將信息嵌入到類型內部是不可以的,因為沒有辦法將信息嵌入指針內部。那麼,一個類型的 traits 信息,必須在類型外部。標准的方法是將它放到 template(模板)以及這個 template(模板)的一個或更多的 specializations(特化)中。對於 iterators(迭代器),標准庫中 template(模板)被稱為 iterator_traits:

template<typename IterT> // template for information about
struct iterator_traits; // iterator types
  就像你能看到的,iterator_traits 是一個 struct(結構體)。根據慣例,traits 總是被實現為 struct(結構體)。另一個慣例就是用來實現 traits 的 structs(結構體)以 traits classes(這可不是我捏造的)聞名。

  iterator_traits 的工作方法是對於每一個 IterT 類型,在 struct(結構體)iterator_traits<IterT> 中聲明一個名為 iterator_category 的 typedef。這個 typedef 被看成是 IterT 的 iterator category(迭代器種類)。

  iterator_traits 通過兩部分實現這一點。首先,它強制要求任何 user-defined iterator(用戶定義迭代器)類型必須包含一個名為 iterator_category 的嵌套 typedef 用以識別適合的 tag struct(標簽結構體)。例如,deque 的 iterators(迭代器)是隨機訪問的,所以一個 deque iterators 的 class 看起來就像這樣:

template < ... > // template params elided
class deque {
 public:
  class iterator {
   public:
    typedef random_access_iterator_tag iterator_category;
    ...
  };
 ...
};
  然而,list 的 iterators(迭代器)是雙向的,所以它們是這樣做的:

template < ... >
class list {
 public:
 class iterator {
  public:
  typedef bidirectional_iterator_tag iterator_category;
  ...
 };
 ...
};
  iterator_traits 僅僅是簡單地模仿了 iterator class 的嵌套 typedef:

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved