Item 47 使用Traits類提供型別資訊

2021-07-10 01:29:02 字數 4573 閱讀 8385

item 47: use traits classes for information about types.

c++中的 traits 類可以在編譯期提供型別資訊,它是用traits模板及其特化來實現的。 通過方法的過載,可以在編譯期對型別進行」if…else」判斷。我們通過stl中的乙個例子來介紹traits的實現和使用。

本文以iterator_traits為例介紹了如何實現traits類,以及如何使用traits類(在item 42中提到過iterator_traits)。 其實c++標準庫中還提供了很多其他的traits,比如char_traits,numeric_limits等。

stl提供了很多的容器、迭代器和演算法,其中的advance便是乙個通用的演算法,可以讓乙個迭代器移動n步:

template

<

typename

itert

,typename

distt

>

void

advance

(itert

&iter

,disttd);

// 如果d小於0,就逆向移動

對於上述五種迭代器,c++提供了五種tag來標識迭代器的型別,它們之間是」is-a」的關係:

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

{};

現在回到advance的問題,它的實現方式顯然取決於iter的型別:

template

<

typename

itert

,typename

distt

>

void

advance

(itert

&iter

,disttd)

// for random access iters

else

// use iterative calls to

else

// ++ or -- for other

}// iterator categories

}

怎麼得到iter的型別呢?這正是traits的作用。

traits允許我們在編譯期得到型別的資訊。traits並非乙個關鍵字,而是乙個程式設計慣例。

traits的另乙個需求在於advance對與基本資料型別也能正常工作,比如char*。所以traits不能借助類來實現, 於是我們把traits放到模板中。比如:

template

<

typename

itert

>

// template for information about

struct

iterator_traits

;// iterator types

iterator_traits將會標識itert的迭代器類別。iterator_traits的實現包括兩部分:

在使用者定義的型別中,typedef該型別支援迭代器的tag,例如deque支援隨機迭代器:

template

<

...>

// template params elided

class

deque

:};

然後在全域性的iterator_traits模板中typedef那個使用者型別中的tag,以提供全域性和統一的型別識別。

template

<

typename

itert

>

struct

iterator_traits

;

上述辦法對基本資料型別的指標是不起作用的,我們總不能在指標裡面typedef乙個tag吧? 其實這時只需要偏特化iterator_traits,因為內建型別指標都是可以隨機訪問的:

template

<

typename

itert

>

// partial template specialization

struct

iterator_traits

<

itert

*>

;

你已經看到了實現乙個traits類的整個過程:

確定你希望提供的型別資訊。比如你希望提供dequeiterator型別;

為那個資訊起乙個名字。比如iterator_catetory

提供乙個模板以及必要的特化,來包含你希望提供的型別資訊。比如iterator_traits

我們已經用iterator_traits提供了迭代器的型別資訊,是時候給出advance的實現了。

template

<

typename

itert

,typename

distt

>

void

advance

(itert

&iter

,disttd)

上述實現其實並不完美,至少if語句中的條件在編譯時就已經決定,它的判斷卻推遲到了執行時(顯然是低效的)。 在編譯時作此判斷,需要為不同的iterator提供不同的方法,然後在advance裡呼叫它們。

template

<

typename

itert

,typename

distt

>

void

advance

(itert

&iter

,disttd)

// 隨機訪問迭代器

template

<

typename

itert

,typename

distt

>

void

doadvance

(itert

&iter

,disttd,

std::

random_access_iterator_tag

)// 雙向迭代器

template

<

typename

itert

,typename

distt

>

void

doadvance

(itert

&iter

,disttd,

std::

bidirectional_iterator_tag

)else

}// 輸入迭代器

template

<

typename

itert

,typename

distt

>

void

doadvance

(itert

&iter

,disttd,

std::

input_iterator_tag

)while(d

--)++iter

;}

總結一下上面**是如何使用traits類的:

建立一系列的」worker」函式,擁有不同的traits引數。根據traits引數來提供相應的實現;

建立乙個」master」函式來呼叫這些」worker」,並將traits類提供的資訊傳遞給」worker」。

STL原始碼 traits的使用

關於iterator traits和type traits的使用,我們什麼時候會使用這兩個類?我們怎麼使用?問題 將 first1,last1 區間內的元素複製一遍。我們需要知道first1迭代器的型別。template iter copy iter first1,iter last1 else n...

爬蟲 使用ItemLoader維護item

在item的filed 中設定引數函式,可以用來預處理item欄位的資料,另一方面也方便程式 的管理和重用 item中 from scrapy.loader.processors import mapcompose,takefirst import scrapy from scrapy.loader...

PHP中的traits簡單使用例項

php 5.4中的traits,是新引入的特性wesppjs,中文還真不知道如何準確翻譯好。其實際的目的,是為了有的場合想用多繼承,但php又沒多繼承,於是就發明了這樣的乙個東西。traits可以理解為一組能被不同的類都能呼叫到的方法集合,但traits不是類!不能被例項化。先來例子看下語法 fun...