stl 中的type traits

来源:互联网 发布:多台服务器数据同步 编辑:程序博客网 时间:2024/06/07 00:40
原文地址:中的type traits">stl 中的type traits作者:fengshao5411

【转】《STL源码剖析》学习笔记2——神奇的__type_traits

已有 82 次阅读 2009-12-21 11:10

http://blog.csdn.net/lonelywinter340/archive/2008/11/15/3297892.aspx

在STL中为了提供通用的操作而又不损失效率,我们用到了一种特殊的技巧,叫traits编程技巧。具体的来说,traits就是通过定义一些结构体或类,并利用模板类特化和偏特化的能力,给类型赋予一些特性,这些特性根据类型的不同而异。在程序设计中可以使用这些traits来判断一个类型的一些特性,引发C++的函数重载机制,实现同一种操作因类型不同而异的效果。traits的编程技巧极度弥补了C++语言的不足 。

举例:

现在定义一个__type_traits可以获得类型的如下属性:

1. 是否存在non-trivial default constructor

2. 是否存在non-trivial copy constructor

3. 是否存在non-trivial assignment operator

4. 是否存在non-trivial destructor

struct __true_type {
};

struct __false_type {
};

template <class _Tp>
struct __type_traits { 

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

问题:为什么把对象的所有的属性都定义为__false_type?

这样是采用最保守的做法,先把所有的对象属性都设置为__false_type,然后在针对每个基本数据类型设计特化的__type_traits,就可以达到预期的目的,如可以定义__type_traits<int>如下:

template <>

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

template <>

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

    ......

    ......

其他基本类型的traits也可以有相应的定义

__type_traits的偏特化版本

template <class _Tp>
struct __type_traits<_Tp*>{
   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;
};

我们可以自定义__type_traits的特化版本

比如对与自定义的Shape类型,我们可以这样定义__type_traits<Shape>

struct __type_traits<Shape>{
   typedef __false_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;
};

如果编译器够厉害,我们甚至可以不用自己去定义特化的__type_traits,编译器就能够帮我们搞定:)

如何使用呢?

假设现在用个模板函数fun需要根据类型T是否有non-trivialconstructor来进行不同的操作,可以这样来实现:

template<class T>

void fun()

{

     typedef typename__type_traits<T>::has_trivial_constructor_Trivial_constructor;

    __fun(_Trivial_constructor()); //根据得到的_Trivial_constructor来调用相应的函数

}

// 两个重载的函数

void __fun(__true_type )    

{ .....  }

void __fun(__false_type )

{ ...... }

 

看了这篇文章,对traits又重新巩固了一下。

其一traits实现的功能就类似于以前c里面(当然c++里也很常见)的控制参数,if 参数等于多少 else。。。。,当然实现某个功能这两者都没有什么问题,一个是编译器决定一个是运行期决定。但是设计的框架,基础库就不一样了,它们注重的是通用,易扩展,如果使用控制参数当然就变得十分的困难,这就又和设计模式有关了。traits的实现就是符合了面向对象设计的开闭原则。

其二traits充分的利用了摸板特化的技巧,通过特化函数重载让编译器来选择正确的类型处理方式,在后续的扩展,自定义特化扩展方面都很容易。

其三traits在使用上面看是很普通的一些特化方面的使用,而之所以叫typetraits是因为对多种类型经过深入分析,提取出这些类型共有的并存在差异的特性提取出来,使之成为处理方式不同的依据。

研究比较浅,所以只是从表面上分析一下,见笑!