c++ template之trait技法總結

Trait技法的最初目的是爲了管理模板參數,有的時候模板中需要幾個參數,但是往往有些參數是與main parameters緊密相關的,這時候可以使用trait技巧,從幾個主要的模板參數中推導出相應的secondary template argument,並以默認模板參數的形式出現在模板中。實際上使用的trait技巧實例往往會有效地提高程序的效率,下面我結合STL小小的說說trait的實際運用。

1、SGI STL中的__type_traits

類型粗略的講有兩種,一種是用class封轉,並且它的複製拷貝很費時,比如需要深度複製,需要safe copying——即需要調用構造函數完成複製;另一種是所謂的POD(plain old data),一般是build-in類型或是c式的struct類型,這種類型複製和拷貝時只需直接複製內存塊就可以了,於是有了bitwise copying或是trival construct/deconstruct/copy/assignment的概念。

SGI STL中使用__type_traits就可以在編譯期間就確定複製一個對象是調用賦值構造函數還是直接調用memcpy,從而提高效率。看SGI STL的源代碼:

struct __true_type {};
struct __false_type {};

template <class type>   //primariy template
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;
};
__STL_TEMPLATE_NULL struct __type_traits<char> { //full specialization
   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<int> {
   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;
};
......//針對其他build-in類型的特化
接下來,看看怎樣使用__type_trairt:

template <class InputIterator, class ForwardIterator, class T>
inline ForwardIterator __uninitialized_copy(InputIterator first, InputIterator last,
                     ForwardIterator result, T*) {
  typedef typename __type_traits<T>::is_POD_type is_POD;
  return __uninitialized_copy_aux(first, last, result, is_POD());
}
template <class InputIterator, class ForwardIterator> inline ForwardIterator 
__uninitialized_copy_aux(InputIterator first, InputIterator last,
                         ForwardIterator result, __true_type) {
  return copy(first, last, result); //STL 算法copy裏面大有乾坤,針對POD類型,調用memmove,還含有iterator_trait的使用
}
template <class InputIterator, class ForwardIterator>
ForwardIterator __uninitialized_copy_aux(InputIterator first, InputIterator last,
                         ForwardIterator result, __false_type) {
  ForwardIterator cur = result;
    for ( ; first != last; ++first, ++cur)
      construct(&*cur, *first);
    return cur;
  }
}
其他的如uninitialized_fill、uninitialized_fill_n也是類似的。還有《C++ template》中的CSMTraits也很能說明trait的強大之處。

2、STL中的iterator_traits

iterator_traits定義了迭代器的value type、different type、reference type、pointer type和iterator_category類型,我們只說最後一個。

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 {};
template <class T, class Distance> struct input_iterator {
  typedef input_iterator_tag iterator_category;
};
struct output_iterator {
  typedef output_iterator_tag iterator_category;
};
template <class T, class Distance> struct forward_iterator {
  typedef forward_iterator_tag iterator_category;
};
template <class T, class Distance> struct bidirectional_iterator {
  typedef bidirectional_iterator_tag iterator_category;
};
template <class T, class Distance> struct random_access_iterator {
  typedef random_access_iterator_tag iterator_category;
};
//iterator_traits的使用
template <class InputIterator, class Distance>
inline void advance(InputIterator& i, Distance n) {
  __advance(i, n, iterator_traits<InputIterator>::iterator_category()); //構造一個臨時的xx_iterator_tag對象
}
template <class InputIterator, class Distance>
inline void __advance(InputIterator& i, Distance n, input_iterator_tag) {
  while (n--) ++i;
}
template <class BidirectionalIterator, class Distance>
inline void __advance(BidirectionalIterator& i, Distance n, 
                      bidirectional_iterator_tag) {
  if (n >= 0)
    while (n--) ++i;
  else
    while (n++) --i;
}
template <class RandomAccessIterator, class Distance>
inline void __advance(RandomAccessIterator& i, Distance n, 
                      random_access_iterator_tag) {
  i += n;
}


3、STL中的char_traits

與trait相關的還有policy技巧,trait更偏向於從主模板參數推導出與之緊密相關的類型或常量等信息,而policy更偏向於行爲方面的信息,如函數。trait與policy的界限有些模糊,實際上有的書也有property trait和policy trairt的概念,由此也可以看出,policy類似於定義的一種算法(函數),而與主模板參數沒有很緊密的邏輯聯繫。


參考書籍:《STL源碼剖析》

  《C++ template》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章