我们知道Traits是C++语言的一种高级特性。STL首先利用Traits技术对迭代器的特性做出规范, 制定出iterator_traits。后来SGI STL把它应用在迭代器以外的地方, 就有了type_traits的叫法。
我的理解是type traits是算法用来获取对象的一些重要信息,比如说是不是class,是不是function,有没有const, signed, volatile这些修饰符,有没有无用的构造函数之类的技术,根据 对象的这些信息就可以实现相关的操作。关于type traits的详细资料可参见
http://www.cplusplus.com/reference/type_traits/?kw=type_traits
有人可能会奇怪为什么要用traits或type_traits这些奇奇怪怪,绕来绕去的东西。用虚函数实现多态不就可以运行的时候实现不同的行为了吗?我的理解是,traits是编译时候就能决定的,虚函数多态是运行时候决定的,还得去查虚函数表,这样就比较慢。说白了还是为了效率的缘故 。
Traits和Type Traits实现的基础是函数模板+偏特化。如下图所示:
注意这是C++ G2.9的代码。Type Traits首先定义了_true_type和_false_type这两个structure。然后给出了泛化和针对int和double的两个特化版本。可以看出,因为int和double都是Plain Old Data(POD)类型,所以它们的default_constructor, copy_constructor, assignment_operator, destructor 这些东西都不重要,其实根本就不需要,所以它们的has_trivial_xxxx都被定义为_true_type。而泛化版本的这些缺省都是 _false_type。这样,当算法询问一个 POD类型的对象有没有copy_contructor的时候, 就知道答案为否。
我们看看对于一个比较简单的class(不含指针),它的这些has_trival_xxxx会返回什么呢?我们可以测试一下这个Foo类:
class Foo
{
private:
int d1, d2;
};
测试结果
__has_trivial_assign 1
__has_trivial_copy 1
__has_trivial_constructor 1
__has_trivial_destructor 1
这个符合预期,因为class foo里面没有指针,所以上面4个函数都不重要,C++编译器给它们提供的缺省函数就够了。
我们再测试一下list,返回结果为
__has_trivial_assign 0
__has_trivial_copy 0
__has_trivial_constructor 0
__has_trivial_destructor 0
这个也符合预期, 因为list里面有指针嘛。
看来这个type traits很智能啊。它是怎么实现的呢?
对于POD类型,我们举一个简单的type traits is_integral,它用来看一个类型是不是整型,如果该类型是int/unsigned int/long/unsigned long/long long/unsigned long long/bool/char/signed char/unsigned char 之一,就返回true,否则就是false。
其具体实现如下
我们可以看出它其实就是在玩类模板和特化而已。
如果深入到类的话,应该就没这么简单了。应该是编译器里面加了很多代码,比如说看一个class的话里面有没有指针,从而做出相应判断。