item 47: use traits classes for information about types.c++中的 traits 類可以在編譯期提供型別資訊,它是用traits模板及其特化來實現的。 通過方法的過載,可以在編譯期對型別進行」if…else」判斷。我們通過stl中的乙個例子來介紹traits的實現和使用。
本文以stl提供了很多的容器、迭代器和演算法,其中的iterator_traits
為例介紹了如何實現traits類,以及如何使用traits類(在item 42中提到過iterator_traits
)。 其實c++標準庫中還提供了很多其他的traits,比如char_traits
,numeric_limits
等。
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類的整個過程:
確定你希望提供的型別資訊。比如你希望提供deque
的iterator
型別;
為那個資訊起乙個名字。比如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...