您的位置:首页 > 编程语言 > C语言/C++

c++ template之trait技法总结

2012-03-19 21:20 525 查看
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》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: