国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

C++箴言:為類(lèi)型信息使用特征類(lèi)

2019-11-17 05:12:27
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

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

template// move iter d units
void advance(IterT& iter, DistT d); // forward; if d < 0,
// move iter backward

  在概念上,advance 僅僅是在做 iter += d,但是 advance 不能這樣實(shí)現(xiàn),因?yàn)橹挥?random access iterators(隨機(jī)訪問(wèn)迭代器)支持 += Operation。不夠強(qiáng)力的 iterator(迭代器)類(lèi)型不得不通過(guò)反復(fù)利用 ++ 或 -- d 次來(lái)實(shí)現(xiàn) advance。

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

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

  bidirectional iterators(雙向迭代器)為 forward iterators(前向迭代器)加上了和向前一樣的向后移動(dòng)的能力。STL 的 list 的 iterators(迭代器)屬于這一種類(lèi),set,multiset,map 和 multimap 的 iterators(迭代器)也一樣。

  最強(qiáng)力的 iterator category(迭代器種類(lèi))是 random access iterators(隨機(jī)訪問(wèn)迭代器)。這種 iterators(迭代器)為 bidirectional iterators(雙向迭代器)加上了 "iterator arithmetic"(“迭代器運(yùn)算”)的能力,也就是說(shuō),在常量時(shí)間里向前或者向后跳轉(zhuǎn)一個(gè)任意的距離。這樣的運(yùn)算類(lèi)似于指針運(yùn)算,這并不會(huì)讓人感到驚奇,因?yàn)?random access iterators(隨機(jī)訪問(wèn)迭代器)就是以 built-in pointers(內(nèi)建指針)為原型的,而 built-in pointers(內(nèi)建指針)可以和 random access iterators(隨機(jī)訪問(wèn)迭代器)有同樣的行為。vector,deque 和 string 的 iterators(迭代器)是 random access iterators(隨機(jī)訪問(wèn)迭代器)。

  對(duì)于五種 iterator categories(迭代器種類(lèi))中的每一種,C++ 都有一個(gè)用于識(shí)別它的 "tag strUCt"(“標(biāo)簽結(jié)構(gòu)體”)在標(biāo)準(zhǔn)庫(kù)中:

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 {};

  這些結(jié)構(gòu)體之間的 inheritance relationships(繼續(xù)關(guān)系)是正當(dāng)?shù)?is-a 關(guān)系:所有的 forward iterators(前向迭代器)也是 input iterators(輸入迭代器),等等,這都是成立的。我們不久就會(huì)看到這個(gè) inheritance(繼續(xù))的功用。

  但是返回到 advance。對(duì)于不同的 iterator(迭代器)能力,實(shí)現(xiàn) advance 的一個(gè)方法是使用反復(fù)增加或減少 iterator(迭代器)的循環(huán)的 lowest-common-denominator(最小共通特性)策略。然而,這個(gè)方法要花費(fèi) linear time(線性時(shí)間)。random access iterators(隨機(jī)訪問(wèn)迭代器)支持 constant-time iterator arithmetic(常量時(shí)間迭代器運(yùn)算),當(dāng)它出現(xiàn)的時(shí)候我們最好能利用這種能力。

  我們真正想做的就是大致像這樣實(shí)現(xiàn) advance:

template
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 是否是一個(gè) random access iterators(隨機(jī)訪問(wèn)迭代器),依次下來(lái),就需要知道它的類(lèi)型,IterT,是否是一個(gè) random access iterators(隨機(jī)訪問(wèn)迭代器)類(lèi)型。換句話說(shuō),我們需要得到關(guān)于一個(gè)類(lèi)型的某些信息。這就是 traits 讓你做到的:它們答應(yīng)你在編譯過(guò)程中得到關(guān)于一個(gè)類(lèi)型的信息。 traits 不是 C++ 中的一個(gè)要害字或預(yù)定義結(jié)構(gòu);它們是一項(xiàng)技術(shù)和 C++ 程序員遵守的慣例。建立這項(xiàng)技術(shù)的要求之一是它在 built-in types(內(nèi)建類(lèi)型)上必須和在 user-defined types(用戶定義類(lèi)型)上一樣有效。例如,假如 advance 被一個(gè)指針(譬如一個(gè) const char*)和一個(gè) int 調(diào)用,advance 必須有效,但是這就意味著 traits 技術(shù)必須適用于像指針這樣的 built-in types(內(nèi)建類(lèi)型)。

  traits 對(duì) built-in types(內(nèi)建類(lèi)型)必須有效的事實(shí)意味著將信息嵌入到類(lèi)型內(nèi)部是不可以的,因?yàn)闆](méi)有辦法將信息嵌入指針內(nèi)部。那么,一個(gè)類(lèi)型的 traits 信息,必須在類(lèi)型外部。標(biāo)準(zhǔn)的方法是將它放到 template(模板)以及這個(gè) template(模板)的一個(gè)或更多的 specializations(特化)中。對(duì)于 iterators(迭代器),標(biāo)準(zhǔn)庫(kù)中 template(模板)被稱(chēng)為 iterator_traits:

template// template for information about
struct iterator_traits; // iterator types

  就像你能看到的,iterator_traits 是一個(gè) struct(結(jié)構(gòu)體)。根據(jù)慣例,traits 總是被實(shí)現(xiàn)為 struct(結(jié)構(gòu)體)。另一個(gè)慣例就是用來(lái)實(shí)現(xiàn) traits 的 structs(結(jié)構(gòu)體)以 traits classes(這可不是我捏造的)聞名。

  iterator_traits 的工作方法是對(duì)于每一個(gè) IterT 類(lèi)型,在 struct(結(jié)構(gòu)體)iterator_traits中聲明一個(gè)名為 iterator_category 的 typedef。這個(gè) typedef 被看成是 IterT 的 iterator category(迭代器種類(lèi))。

  iterator_traits 通過(guò)兩部分實(shí)現(xiàn)這一點(diǎn)。首先,它強(qiáng)制要求任何 user-defined iterator(用戶定義迭代器)類(lèi)型必須包含一個(gè)名為 iterator_category 的嵌套 typedef 用以識(shí)別適合的 tag struct(標(biāo)簽結(jié)構(gòu)體)。例如,deque 的 iterators(迭代器)是隨機(jī)訪問(wèn)的,所以一個(gè) deque iterators 的 class 看起來(lái)就像這樣:

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 僅僅是簡(jiǎn)單地模擬了 iterator class 的嵌套 typedef:

// the iterator_category for type IterT is whatever IterT says it is;
// see Item 42 for info on the use of "typedef typename"
template
struct iterator_traits {
 typedef typename IterT::iterator_category iterator_category;
 ...
};

  這樣對(duì)于 user-defined types(用戶定義類(lèi)型)能很好地運(yùn)轉(zhuǎn)。但是對(duì)于本身是 pointers(指針)的 iterators(迭代器)根本不起作用,因?yàn)椴淮嬖陬?lèi)似于帶有一個(gè)嵌套 typedef 的指針的東西。iterator_traits 實(shí)現(xiàn)的第二個(gè)部分處理本身是 pointers(指針)的 iterators(迭代器)。
  為了支持這樣的 iterators(迭代器),iterator_traits 為 pointer types(指針類(lèi)型)提供了一個(gè) partial template specialization(部分模板特化)。pointers 的行為類(lèi)似 random access iterators(隨機(jī)訪問(wèn)迭代器),所以這就是 iterator_traits 為它們指定的種類(lèi):


template// partial template specialization
struct iterator_traits// for built-in pointer types
{
 typedef random_access_iterator_tag iterator_category;
 ...
};

  到此為止,你了解了如何設(shè)計(jì)和實(shí)現(xiàn)一個(gè) traits class:

  ·識(shí)別你想讓它可用的關(guān)于類(lèi)型的一些信息(例如,對(duì)于 iterators(迭代器)來(lái)說(shuō),就是它們的 iterator category(迭代器種類(lèi)))。

  ·選擇一個(gè)名字標(biāo)識(shí)這個(gè)信息(例如,iterator_category)。

  ·提供一個(gè) template(模板)和一系列 specializations(特化)(例如,iterator_traits),它們包含你要支持的類(lèi)型的信息。

  給出了 iterator_traits ——實(shí)際上是 std::iterator_traits,因?yàn)樗?C++ 標(biāo)準(zhǔn)庫(kù)的一部分——我們就可以改善我們的 advance 偽代碼:

template
void advance(IterT& iter, DistT d)
{
 if (typeid(typename std::iterator_traits::iterator_category) ==
  typeid(std::random_access_iterator_tag))
 ...
}

  這個(gè)雖然看起來(lái)有點(diǎn)希望,但它不是我們想要的。在某種狀態(tài)下,它會(huì)導(dǎo)致編譯問(wèn)題,這個(gè)問(wèn)題我們以后再來(lái)研究它,現(xiàn)在,有一個(gè)更基礎(chǔ)的問(wèn)題要討論。IterT 的類(lèi)型在編譯期間是已知的,所以 iterator_traits::iterator_category 可以在編譯期間被確定。但是 if 語(yǔ)句還是要到運(yùn)行時(shí)才能被求值。為什么要到運(yùn)行時(shí)才做我們?cè)诰幾g期間就能做的事情呢?它浪費(fèi)了時(shí)間(嚴(yán)格意義上的),而且使我們的執(zhí)行碼膨脹。

  我們真正想要的是一個(gè)針對(duì)在編譯期間被鑒別的類(lèi)型的 conditional construct(條件結(jié)構(gòu))(也就是說(shuō),一個(gè) if...else 語(yǔ)句)。碰巧的是,C++ 已經(jīng)有了一個(gè)得到這種行為的方法。它被稱(chēng)為 overloading(重載)。

  當(dāng)你重載某個(gè)函數(shù) f 時(shí),你為不同的 overloads(重載)指定不同的 parameter types(形參類(lèi)型)。當(dāng)你調(diào)用 f 時(shí),編譯器會(huì)根據(jù)被傳遞的 arguments(實(shí)參)挑出最佳的 overload(重載)。基本上,編譯器會(huì)說(shuō):“假如這個(gè) overload(重載)與被傳遞的東西是最佳匹配的話,就調(diào)用這個(gè) f;假如另一個(gè) overload(重載)是最佳匹配,就調(diào)用它;假如第三個(gè) overload(重載)是最佳的,就調(diào)用它”等等。看到了嗎?一個(gè)針對(duì)類(lèi)型的 compile-time conditional construct(編譯時(shí)條件結(jié)構(gòu))。為了讓 advance 擁有我們想要的行為方式,我們必須要做的全部就是創(chuàng)建一個(gè)包含 advance 的“內(nèi)容”的重載函數(shù)的多個(gè)版本(此處原文有誤,根據(jù)作者網(wǎng)站勘誤修改——譯者注),聲明它們?nèi)〉貌煌?iterator_category object 的類(lèi)型。我為這些函數(shù)使用名字 doAdvance:

template// use this impl for
void doAdvance(IterT& iter, DistT d, // random access
std::random_access_iterator_tag) // iterators
{
 iter += d;
}

template// use this impl for
void doAdvance(IterT& iter, DistT d, // bidirectional
std::bidirectional_iterator_tag) // iterators
{
 if (d >= 0) { while (d--) ++iter; }
 else { while (d++) --iter; }
}

template// use this impl for
void doAdvance(IterT& iter, DistT d, // input iterators
std::input_iterator_tag)
{
 if (d < 0 ) {
  throw std::out_of_range("Negative distance"); // see below
 }
 while (d--) ++iter;
}

  因?yàn)?forward_iterator_tag 從 input_iterator_tag 繼續(xù)而來(lái),針對(duì) input_iterator_tag 的 doAdvance 版本也將處理 forward iterators(前向迭代器)。這就是在不同的 iterator_tag structs 之間繼續(xù)的動(dòng)機(jī)。
(實(shí)際上,這是所有 public inheritance(公有繼續(xù))的動(dòng)機(jī)的一部分:使針對(duì) base class types(基類(lèi)類(lèi)型)寫(xiě)的代碼也能對(duì) derived class types(派生類(lèi)類(lèi)型)起作用。)

  advance 的規(guī)范對(duì)于 random access(隨機(jī)訪問(wèn))和 bidirectional iterators(雙向迭代器)答應(yīng)正的和負(fù)的移動(dòng)距離,但是假如你試圖移動(dòng)一個(gè) forward(前向)或 input iterator(輸入迭代器)一個(gè)負(fù)的距離,則行為是未定義的。在我檢查過(guò)的實(shí)現(xiàn)中簡(jiǎn)單地假設(shè) d 是非負(fù)的,因而假如一個(gè)負(fù)的距離被傳入,則進(jìn)入一個(gè)直到計(jì)數(shù)降為零的非常長(zhǎng)的循環(huán)。在上面的代碼中,我展示了改為一個(gè)異常被拋出。這兩種實(shí)現(xiàn)都是正確的。未定義行為的詛咒是:你無(wú)法預(yù)知會(huì)發(fā)生什么。

  給出針對(duì) doAdvance 的各種重載,advance 需要做的全部就是調(diào)用它們,傳遞一個(gè)適當(dāng)?shù)?iterator category(迭代器種類(lèi))類(lèi)型的額外 object 以便編譯器利用 overloading resolution(重載解析)來(lái)調(diào)用正確的實(shí)現(xiàn):

template
void advance(IterT& iter, DistT d)
{
 doAdvance( // call the version
  iter, d, // of doAdvance
  typename // that is
  std::iterator_traits::iterator_category() // apPRopriate for
 ); // iter's iterator
} // category

  我們現(xiàn)在能夠概述如何使用一個(gè) traits class 了:

  ·創(chuàng)建一套重載的 "worker" functions(函數(shù))或者 function templates(函數(shù)模板)(例如,doAdvance),它們?cè)谝粋€(gè) traits parameter(形參)上不同。與傳遞的 traits 信息一致地實(shí)現(xiàn)每一個(gè)函數(shù)。

  ·創(chuàng)建一個(gè) "master" function(函數(shù))或者 function templates(函數(shù)模板)(例如,advance)調(diào)用這些 workers,傳遞通過(guò)一個(gè) traits class 提供的信息。

  traits 廣泛地用于標(biāo)準(zhǔn)庫(kù)中。有 iterator_traits,當(dāng)然,再加上 iterator_category,提供了關(guān)于 iterators(迭代器)的四塊其它信息(其中最常用的是 value_type )。還有 char_traits 持有關(guān)于 character types(字符類(lèi)型)的信息,還有 numeric_limits 提供關(guān)于 numeric types(數(shù)值類(lèi)型)的信息,例如,可表示值的最小值和最大值,等等。(名字 numeric_limits 令人有些希奇,因?yàn)殛P(guān)于 traits classes 更常用的慣例是以 "traits" 結(jié)束,但是它就是被叫做 numeric_limits,所以 numeric_limits 就是我們用的名字。)

  TR1引入了一大批新的 traits classes 提供關(guān)于類(lèi)型的信息,包括 is_fundamental(T 是否是一個(gè) built-in type(內(nèi)建類(lèi)型)),is_array(T 是否是一個(gè) array type(數(shù)組類(lèi)型)),以及 is_base_of(T1 是否和 T2 相同或者是 T2 的一個(gè) base class(基類(lèi)))。合計(jì)起來(lái),TR1 在標(biāo)準(zhǔn) C++ 中加入了超過(guò) 50 個(gè) traits classes。

  Things to Remember

  ·traits classes 使關(guān)于類(lèi)型的信息在編譯期間可用。它們使用 templates(模板)和 template specializations(模板特化)實(shí)現(xiàn)。

  ·結(jié)合 overloading(重載),traits classes 使得執(zhí)行編譯期類(lèi)型 if...else 檢驗(yàn)成為可能。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 久治县| 牙克石市| 沂源县| 榆社县| 邵武市| 青龙| 叶城县| 衡阳县| 绥江县| 正蓝旗| 博爱县| 永兴县| 邵阳市| 上高县| 株洲县| 克东县| 怀仁县| 徐水县| 沾益县| 宁陵县| 东方市| 高邮市| 紫云| 双牌县| 宁河县| 奉新县| 辰溪县| 苏州市| 闽侯县| 本溪市| 塔河县| 读书| 湟源县| 甘肃省| 三门县| 秀山| 宁远县| 开阳县| 桃园市| 伊吾县| 恭城|