1. 程式人生 > >STL原始碼分析之__type_traits型別

STL原始碼分析之__type_traits型別

前言

上一篇探討的是traits是為了將迭代器沒能完善的原生指標, traits用特化和偏特化程式設計來完善. 這一篇準備探討__type_traits, 為了將我們在空間配置器裡面的提過的__true_typefalse_type進行解答. 而type_traits型別對我們STL的效率又有什麼影響, 有什麼好處?

__type_traits介紹

前面介紹的Traits技術在STL中彌補了C++模板的不足,但是Traits技術只是用來規範迭代器,對於迭代器之外的東西沒有加以規範。因此,SGI將該技術擴充套件到迭代器之外,稱為__type_traits。iterator_traits是萃取迭代器的特性,而__type_traits是萃取型別的特性。萃取的型別如下:

  • 是否具備non-trivial default ctor?
  • 是否具備non-trivial copy ctor?
  • 是否具備non-trivial assignment operator?
  • 是否具備non-trivial dtor?
  • 是否為POD(plain old data)型別?

其中non-trivial意指非預設的相應函式,編譯器會為每個類構造以上四種預設的函式,如果沒有定義自己的,就會用編譯器預設函式,如果使用預設的函式,我們可以使用memcpy(),memmove(),malloc()等函式來加快速度,提高效率.

__iterator_traits

允許針對不同的型別屬性在編譯期間決定執行哪個過載函式而不是在執行時才處理, 這大大提升了執行效率. 這就需要STL提前做好選擇的準備. 是否為POD, non-trivial型別__true_type__false_type 來區分.

空間配置器的例子

關於__false_type也在空間配置器提過. 現在再來看一看.

// 接受兩個迭代器, 以__type_trais<> 判斷是否有traival destructor 
template <class ForwardIterator, class T>
inline void __destroy(ForwardIterator first,
ForwardIterator last, T*) { typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor; __destroy_aux(first, last, trivial_destructor()); } // non-travial destructor template <class ForwardIterator> inline void __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) { for ( ; first < last; ++first) destroy(&*first); } // travial destructor template <class ForwardIterator> inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}

通過函式trivial_destructor()確定型別來執行更高效的函式. 而且過載函式的選擇實在編譯時期就確定了. 馬上就來探討__false_type__true_type 引數推導.

兩個引數推導

struct __true_type {};
struct __false_type {};

我們不能將引數設為bool值, 因為需要在編譯期就決定該使用哪個函式, 所以需要利用函式模板的引數推導機制, 將__true_type__false_type表現為一個空類, 就不會帶來額外的負擔, 又能表示真假, 還能在編譯時型別推導就確定執行相應的函式.

__type_traits原始碼

__STL_TEMPLATE_NULL struct __type_traits<char> {
   typedef __true_type    has_trivial_default_constructor;
   typedef __true_type    has_trivial_copy_constructor;
   typedef __true_type    has_trivial_assignment_operator;
   typedef __true_type    has_trivial_destructor;
   typedef __true_type    is_POD_type;
};

__STL_TEMPLATE_NULL struct __type_traits<signed char> {
   typedef __true_type    has_trivial_default_constructor;
   typedef __true_type    has_trivial_copy_constructor;
   typedef __true_type    has_trivial_assignment_operator;
   typedef __true_type    has_trivial_destructor;
   typedef __true_type    is_POD_type;
};

...

以上是將基礎的型別都設定為__true_type型別.

#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION

template <class T>
struct __type_traits<T*> {
   typedef __true_type    has_trivial_default_constructor;
   typedef __true_type    has_trivial_copy_constructor;
   typedef __true_type    has_trivial_assignment_operator;
   typedef __true_type    has_trivial_destructor;
   typedef __true_type    is_POD_type;
};

#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */

struct __type_traits<char*> {
   typedef __true_type    has_trivial_default_constructor;
   typedef __true_type    has_trivial_copy_constructor;
   typedef __true_type    has_trivial_assignment_operator;
   typedef __true_type    has_trivial_destructor;
   typedef __true_type    is_POD_type;
};

struct __type_traits<signed char*> {
   typedef __true_type    has_trivial_default_constructor;
   typedef __true_type    has_trivial_copy_constructor;
   typedef __true_type    has_trivial_assignment_operator;
   typedef __true_type    has_trivial_destructor;
   typedef __true_type    is_POD_type;
};

struct __type_traits<unsigned char*> {
   typedef __true_type    has_trivial_default_constructor;
   typedef __true_type    has_trivial_copy_constructor;
   typedef __true_type    has_trivial_assignment_operator;
   typedef __true_type    has_trivial_destructor;
   typedef __true_type    is_POD_type;
};

這裡將指標進行特化處理, 同樣是__true_type型別.

SGI將所有的內嵌型別都定義為false_type, 這是對所有的定義最保守的值.

template <class type>
struct __type_traits { 
   typedef __true_type     this_dummy_member_must_be_first;
   typedef __false_type    has_trivial_default_constructor;
   typedef __false_type    has_trivial_copy_constructor;
   typedef __false_type    has_trivial_assignment_operator;
   typedef __false_type    has_trivial_destructor;
   typedef __false_type    is_POD_type;
};

從上面的原始碼可以明白, 所有的基本型別都是設定的為__true_type型別, 而所有的物件都會被特化為__false_type型別, 這是為了保守而不得這樣做. 也因為__true_type型別讓我們在執行普通型別時能夠以最大效率進行對其的copy, 析構等操作.

總結

SGI對traits進行擴充套件,使得所有型別都滿足traits程式設計規範, 這樣SGI STL演算法可以通過__type_traits獲取型別資訊在編譯期間就能決定出使用哪一個過載函式, 解決了template是在執行時決定過載選擇的問題. 並且通過truefalse來確定POD和travial destructor, 讓程式能選擇更加符合其型別的處理函式, 大大提高了對基本型別的快速處理能力並保證了效率最高.