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    //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 { //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 {
   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 
inline ForwardIterator __uninitialized_copy(InputIterator first, InputIterator last,
                     ForwardIterator result, T*) {
  typedef typename __type_traits::is_POD_type is_POD;
  return __uninitialized_copy_aux(first, last, result, is_POD());
}
template  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 
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  struct input_iterator {
  typedef input_iterator_tag iterator_category;
};
struct output_iterator {
  typedef output_iterator_tag iterator_category;
};
template  struct forward_iterator {
  typedef forward_iterator_tag iterator_category;
};
template  struct bidirectional_iterator {
  typedef bidirectional_iterator_tag iterator_category;
};
template  struct random_access_iterator {
  typedef random_access_iterator_tag iterator_category;
};
//iterator_traits的使用
template 
inline void advance(InputIterator& i, Distance n) {
  __advance(i, n, iterator_traits::iterator_category()); //构造一个临时的xx_iterator_tag对象
}
template 
inline void __advance(InputIterator& i, Distance n, input_iterator_tag) {
  while (n--) ++i;
}
template 
inline void __advance(BidirectionalIterator& i, Distance n, 
                      bidirectional_iterator_tag) {
  if (n >= 0)
    while (n--) ++i;
  else
    while (n++) --i;
}
template 
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》

你可能感兴趣的:(《STL源码剖析》学习笔记)