最近在看fastertransfomer源碼,其中裏面涉及到不少trait的技巧,記得之前在看stl的時候有涉及過,簡單對該方法進行簡單記錄。
在STL中,算法和容器是隔離開的,比如排序算法適用於vector,list,queue,而算法和容器的聯繫的橋樑就是迭代器,迭代器簡單說
就是一個包裝好的指針,算法可以利用指針來實現,現在有一問題,如果該算法函數要返回該指針指向的類型,那麼該模板函數該怎麼寫:
template<class T>
(?) double(T iterator)
{
do something;
return 2*(*iterator)
}
爲了解決這個問題,直觀的想法是迭代器這個類中有其對象所指的類型,如下:
template <class T>
class MyIter {
typedef T value_type; // A nested type declaration, important!!!
T* ptr;
MyIter(T* p = 0) : ptr(p) {}
T& operator*() const { return *ptr; }
};
那麼?則可以用typename T::value_type來代替,其實這裏基本解決了問題,爲了進一步適用廣泛,比如內置類型指針就沒辦法,爲此加一箇中間層:iterator_trait
//普通迭代器
template <class I>
struct iterator_traits
{
Typedef I::value_type value_type;
}
//內置類型,比如int
template <class I>
struct itertor_traits<T*>
{
typedef T value_type;
};
//最終的函數
template <class I>
typename iterator_traits<I>::value_type func(I ite)
{
return *ite;
}
iterator_trait就是利用偏特化實現的一萃取操作,嗯,整個流程看起來的核心思想就是通過trait拿出了指針的指向類型,一定程度上封裝了不同類型指針的獲取指向類型的細節,用戶可以不用關心模板傳進來的指針類型,通過模板配合trait方法設計算法的人員可以更加省心省力。
其他利用場景:
一般來說,如果我們涉及到一個類型決定一批類型的時候,那麼就可以設置一個模板類trait,把這些受影響的類型都放在trait中,
//定義一個模板(空殼子)
template <class T>
class Trait;
//實例化1
template <>
class Trait<class1>
{
typedef class1 datatype;
typedef float* ptrtype;
}
//實例化2
tempalte <>
class Trait<class2>
{
typedef class2 datatype;
typedef int* ptrtype;
}
//偏特化,下面這個就可以用在內置類型裏
template <class T>
class Trait<T*>
{
//do something
}