讀書筆記 Effective C

2022-03-01 13:32:29 字數 3084 閱讀 1292

這一條款主要來討論模板中迭代器的屬性iterator_category,它可以通過類似於vector::iterator::iterator_category的方式來取得。

到這裡我們有必要學習一下stl迭代器的型別,總共有五種,分別是:

input_iterator:唯讀,只能逐個前移

output_iterator:只寫,只能逐個前移

forward_iterator:可讀可寫,只能逐個前移

bidirectional_iterator:可讀可寫,支援逐個前移和後移

random_access_iterator:可讀可寫,支援隨機訪問(任意步數移動)

為了表明容器內使用的是哪一種迭代器,stl在定義迭代器會總會打個乙個標記「tag」,每個tag都是乙個空的結構體,對應於以上五種迭代器,tag也有五個:

struct input_iterator_tag{};

struct output_iterator_tag{};

struct forward_iterator_tag: public input_iterator_tag{};

bidirectional_iterator: public forward_iterator_tag{};

random_access_iterator: public bidirectional_iterator_tag{};

注意這五個tag之間,有些存在繼承關係。

這個標記有什麼用呢?stl在寫vector的時候,會這樣:

1 template class

2class

vector311

…12}13

14寫list的時候,會這樣寫:

15 template class

16class

list

1725

…26 }

既然迭代器已經由tag說明了它的型別(雙向的,還是隨機訪問),那我們如何去利用它呢?比如現在我想要寫乙個迭代器前移的通用函式doadvance,不同迭代器型別會有不同的實現方式,所以我們可以像下面這樣:

1 template 

2void

doadvance(t container)39

else

if (typeid(iteratorcategory) ==typeid(output_iterator_tag))

1013

else

if (typeid(iteratorcategory) ==typeid(forward_iterator_tag))

1417

else

if (typeid(iteratorcategory) ==typeid(bidirectional_iterator_tag))

1821

else

if (typeid(iteratorcategory) ==typeid(random_access_iterator_tag))

2225 }

引數t是容器的型別,比如vector,如果像下面這樣呼叫:

1 vectorv;

2 doadvance(v);

那麼輸出是do manner in random_access_iterator_tag,因為vector的迭代器是隨機訪問型的,可以按隨機訪問型別的處理方式來去實現前移操作。typeid返回結果是名為type_info的標準庫型別的物件的引用,它指明了這個物件/定義的型別。

因為這裡討論的是迭代器,所以更常見的是直接傳迭代器進去,像這樣:

1 template 

2void

doadvance(itert iter)39

…10 }

注意這裡的模板引數是itert,它表示乙個迭代器的型別,比如vector::iterator。這裡是去主動訪問iterator裡面定義的屬性iterator_category,我們也可以通過trait classes來訪問,像下面這樣:

1 template 

2void

doadvance(itert iter)39

…10 }

iterator_traits的定義如下:

1 template

2struct iterator_traits3

;

這個感覺只是簡化了輸入**量而已,本質上還是去獲得迭代器的tag,它有乙個針對指標的偏特化版本,像下面這樣:

1 template

2struct iterator_traits3

;

這裡都是用typeid去進行型別判斷的,它是在執行期才能執行,那麼能不能放在編譯期呢,當然可以,就是要用到函式的過載,像下面這樣:

1 template 

2void

doadvance(itert iter, input_iterator_tag)36

78 template

9void

doadvance(itert iter, random_access_iterator_tag)

10

像下面這樣使用;

1 vector::iterator iter;

2 doadvance(iter, iterator_traitsint>::iterator>::iterator_category());

注意迭代器的tag是可以直接作為函式形參的,這樣就可以在編譯期決定到底執行哪一種迭代器的行為了。

條款標題的traint classes是乙個廣義的概念,我們之前討論的iterator_traits只是其一部分,除以之外,還有四份迭代器相關的資訊(如value_type等),tr1匯入許多新的trait classes,比如is_fundamental等(判斷t是否是內建型別)。

最後,我們來總結一下:

1. traits class使得型別相關資訊可以在編譯期可用,它們以template和template特化完成實現;

2. 整合過載技術後,traits classes有可能在編譯期對型別執行if-else測試。

《effective C 》讀書筆記

1,c 關鍵字explicit c 中,乙個引數的 建構函式 或者除了第乙個引數外其餘引數都有預設值的多參建構函式 承擔了兩個角色。1 是個 構造器,2 是個預設且隱含的型別轉換操作符 所以,有時候在我們寫下如 aaa 這樣的 且恰好 的型別正好是aaa單引數構造器的引數型別,這時候 編譯器就自動呼...

Effective C 讀書筆記

一 讓自己習慣c 1 條款01 視c 為聯邦語言 c 的組成可分為四部分 1.c c 仍然以c語言為基礎。區塊 語句 預處理 內建資料型別 陣列 指標等都來自c。2.object oriented c c with classes所訴說的 classes 包括構造和析構 封裝 繼承 多型 virtu...

讀書筆記 Effective C

部分條款過於深奧,部分條款已了然於心,僅記錄當下所識所學 對於常量巨集定義,最好用const代替 define 對於函式巨集定義,最好用inline代替 define include ifdef ifndef仍被需要 內建物件記得手動初始化 使用成員初始列替換賦值操作 以local static替換...