traits编程是对实体特性的萃取,这里的特性,可以指属性或行为特征。顾名思义,type_traits就是对类型的特性萃取,对每个C++类型,都有如下几种重要特性:
- has_trivial_default_constructor(默认构造函数)
- has_trivial_copy_constructor(拷贝构造函数)
- has_trivial_assignment_operator(赋值运算符)
- is_POD_type(标准布局结构)
当我们对一个类使用如type_traits<T>: :has_trivial_default_constructor,就能萃取出与构造函数相关的特性信息,于是,根据这个类型对应的特性,就可以采取最有效率的措施。
那么如何使用这些特性呢?通常是在定义与这些特性相关的模版方法时。C++普遍的使用了泛化的思想,比如要定义一个分配内存的构造器,每种类型的内存分配方式是应该有差别的,但将所有类型的构造器都定义一次进行重载显然不是一个聪明的做法,可以通过定义一个模版方法使得所有类型共用同一个构造器模版,这时作为分配的具体判断条件的就是这些类型的特性了。所以以上的几种特性应该是作为一种真假值,那么这个值是bool值吗?
先抛开以上所说的type_traits,定义一个关于traits的例子如下:
template<class T>
struct type_traits //公共模版
{
static const bool isInt = false;
};
template<>
struct type_traits<int> //特化
{
static const bool isInt = true;
};
template<class T>
std::string type(T obj)
{
if (type_traits<T>::isInt)
return "it's int type";
else
return "it's not int type";
}
int main(void)
{
std::cout << type(2) << std::endl;
std::cout << type('a') << std::endl;
return 0;
}
运行结果:,这么看起来,是可以使用bool值的。
而在SGI STL中,定义type_traits时使用的是一个拥有真假性质的对象,定义方式如下:
struct _true_type { };
struct _false_type { };
template<class T>
struct type_traits
{
typedef _false_type isInt;
};
template<>
struct type_traits<int>
{
typedef _true_type isInt;
};
template<class T>
std::string type(T obj)
{
typename type_traits<T>::isInt isInt;
return _type(T, isInt);
}
template<class T>
std::string _type(T obj, _true_type)
{
return "it's int type";
}
template<class T>
std::string _type(T obj, _false_type)
{
return "it's not int type";
}
int main(void)
{
std::cout << type(2) << std::endl;
std::cout << type('a') << std::endl;
return 0;
}
结果是相同的:
可以看到这两种定义的方式从根本上来说是真假值的类型不同,从目的上来说是条件判断的方式不同。前者使用的是bool值,而后者则声明为了一个类型,之所以这样设计,是因为各自的使用方式不同,bool值可以直接通过if else等条件分支语句直接使用,而对象值要通过编译器来判断参数类型去选择合适的重载函数。在《STL源码剖析》中写到:
我们希望上述式子影响我们“真”或“假”,但结果不应该是个bool值,应该是个有着真/假性质的“对象”,因为我们希望利用其响应结果来进行参数推导,而编译器只有面对class object形式的参数才会做出参数推导。
虽然是有这么一段话,但我目前并发现这个参数推导的必要性,所以姑且认为两种方式都可以吧。。
这样,所有需要特化的类型萃取都能很容易的定义出来了。部分源码如下:
struct _true_type { };
struct _false_type { };
template<class T>
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;
typedef _false_type is_POD_type;
};
template<>
struct _type_traits<bool>
{
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;
};
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;
typedef _true_type is_POD_type;
};
template<>
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;
};
·
·
·
参考源码:TypeTraits.h