SGISTL源码探究-traits技法

前言

在上一小节中,我们提到了迭代器的相应型别,其中之一的便是value_type,它是根据函数模板的参数推导机制获取到的。但是需要考虑一种另外的情况,当数据类型不是对象的时候,这种时候很明显无法再在类中typedef T value_type了,而是一个普通的int *指针,那么我们如何得到它的value_type。只用将原生指针进行特殊处理就行了(模板的偏特化),这里就引入了traits,专门用来获取到迭代器的相关类型。

iterator_traits

下面直接看它的源码,里面用到了模板偏特化,大意就是可以在模板泛化中设计一个特别的版本,即将某种template参数指定明确的类型等。

#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
/* 这样看来只是多了一层间接性
 * 因为本来Iterator中就有这些类型,还要放在iterator_traits重新typedef一次
 * 这样做的目的就是为了特化的版本(为原生指针提供其相应类型)
 */
template <class Iterator>
struct iterator_traits {
  typedef typename Iterator::iterator_category iterator_category;
  typedef typename Iterator::value_type        value_type;
  typedef typename Iterator::difference_type   difference_type;
  typedef typename Iterator::pointer           pointer;
  typedef typename Iterator::reference         reference;
};
/* 特化版本,迭代器是个原生指针
 * 这样就能将原生指针的相应型别获取到了
 * 可以看到原生指针的iterator_category是random_access_iterator_tag型的
 */
template <class T>
struct iterator_traits<T*> {
  typedef random_access_iterator_tag iterator_category;
  typedef T                          value_type;
  typedef ptrdiff_t                  difference_type;
  typedef T*                         pointer;
  typedef T&                         reference;
};

/* 这里还要针对const T*特化
 * 否则还是依照上一个特化版本的话,得到的是value_type是const int而不是int
 */
template <class T>
struct iterator_traits<const T*> {
  typedef random_access_iterator_tag iterator_category;
  typedef T                          value_type;
  typedef ptrdiff_t                  difference_type;
  typedef const T*                   pointer;
  typedef const T&                   reference;
};
/* 这里用到了一个typename,它的作用是声明当前的iterator_traits是一种类型
 * 这个在effectiveC++里面交代的很清楚
 * 在前面一节中我们看到了iterator_category的用法
 * 这里可以很直观的看到它就是构造并返回了当前迭代器的iterator_category空类的对象
 */
template <class Iterator>
inline typename iterator_traits<Iterator>::iterator_category
iterator_category(const Iterator&) {
  typedef typename iterator_traits<Iterator>::iterator_category category;
  return category();
}
/* 这里用到了0可以转换成指针的性质
 * 相当于返回一个空指针
 */
template <class Iterator>
inline typename iterator_traits<Iterator>::difference_type*
distance_type(const Iterator&) {
  return static_cast<typename iterator_traits<Iterator>::difference_type*>(0);
}

template <class Iterator>
inline typename iterator_traits<Iterator>::value_type*
value_type(const Iterator&) {
  return static_cast<typename iterator_traits<Iterator>::value_type*>(0);
}

这样一来,我们就可以获取到任何类型的相应型别了,之所以使用traits获取这些类型,也是为了将STL的效率提升到极至。比如在上一小节举的关于distance函数的例子,这里我们再把advance的函数列出感受一下traits带给我们的好处:

/* advance调用iterator_category获取到迭代器的类型,根据类型的不同,选择效率最高的方式
 * 比如类型是random_access_iterator_tag时,就可以直接对迭代器进行跳跃移动,不需要循环依次移动
 */
template <class InputIterator, class Distance>
inline void __advance(InputIterator& i, Distance n, input_iterator_tag) {
  while (n--) ++i;
}

#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma set woff 1183
#endif

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;
}

#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma reset woff 1183
#endif

template <class RandomAccessIterator, class Distance>
inline void __advance(RandomAccessIterator& i, Distance n,
                      random_access_iterator_tag) {
  i += n;
}

template <class InputIterator, class Distance>
inline void advance(InputIterator& i, Distance n) {
  __advance(i, n, iterator_category(i));
}

type_traits

SGISTL将traits扩展到了可以获取类型的特性,比如该类型是否有non-trivial assignment等函数,这样就可以采取适合对当前对象比较有效率的做法。比如如果是trivial拷贝构造函数,那么直接调用memcpy就行了,而不用去调用它。

它主要可以获取到对象如下的特性:

  • has_trivial_default_constructor:是否有无用的默认构造函数
  • has_trivial_copy_constructor:是否有无用的默认拷贝构造函数
  • has_trivial_assignment_operator:是否有无用的赋值函数
  • has_trivial_destructor:是否有无用的析构函数
  • is_POD_type:plain old data,是指标量类型或C的struct类型,POD类别必有trivial ctor/dtor/copy/assignment函数

该对象的类型是否具有这些特性,对应了truefalse,但是我们不能将其设为bool值,因为我们需要在编译期就决定该使用哪个函数,所以需要利用函数模板的参数推导机制。因为truefalse,我们将其表现为一个空类。

源码如下

/* __true_type和__false_type,两个空类 */
struct __true_type {
};

struct __false_type {
};

/* 将基础类型的特性特化成__true_type */
template <class type>
struct __type_traits {
   typedef __true_type     this_dummy_member_must_be_first;
                   /* Do not remove this member. It informs a compiler which
                      automatically specializes __type_traits that this
                      __type_traits template is special. It just makes sure that
                      things work if an implementation is using a template
                      called __type_traits for something unrelated. */

   /* The following restrictions should be observed for the sake of
      compilers which automatically produce type specific specializations
      of this class:
          - You may reorder the members below if you wish
          - You may remove any of the members below if you wish
          - You must not rename members without making the corresponding
            name change in the compiler
          - Members you add will be treated like regular members unless
            you add the appropriate support in the compiler. */


   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;
};



// Provide some specializations.  This is harmless for compilers that
//  have built-in __types_traits support, and essential for compilers
//  that don't.

/* 针对char类型特化 */
__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;
};

/* 针对signed char类型特化 */
__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;
};

/* 针对unsigned char类型特化 */
__STL_TEMPLATE_NULL 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;
};

/* 针对short类型特化 */
__STL_TEMPLATE_NULL struct __type_traits<short> {
   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;
};

/* 针对unsigned char类型特化 */
__STL_TEMPLATE_NULL struct __type_traits<unsigned short> {
   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;
};

#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */

可以看到,针对数据类型是基本数据类型的情况,所有特性都是__true_type,但是如果是针对对象,很有可能全部的特性都被置成__false_type,不管它是否是POD型,这跟编译器有关,你也可以自己添加代码在这个头文件中,表明你的对象的特性。

小结

在本小节中,主要分析了traits编程技法以及如何获取迭代器的五种相应型别,如果是对象,则可以依据模板的参数推导机制来获取,但是如果是基础的数据类型,只有使用模板的偏特化。这样我们便可以通过迭代器取得关于对象的数据类型等信息,这样做的其中一个好处就是可以提高一些算法的效率。
比如我们可以使用value_type获取到迭代器指向的对象的数据类型,再使用__type_traits机制,判断该对象的某个特性是__true_type还是__false_type而采取最佳方法。需要注意的是,这些取得的数据类型之类的,都是以对象的形式,利用模板的参数推导在编译期就已经决定了具体使用哪个函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值