Traits
技术
(转自http://comparative.spaces.live.com/blog/)
1.
概念
Trait的中文意思就是特性,Traits就像特性萃取机,榨取不同类的特性,以便能统一处理。Traits依靠显式模板特殊化(explicit template specialization)来把代码中因类型不同而发生变化的片断拖出来,用统一的接口来包装。这个接口可以包含一个C++类所能包含的任何东西:内嵌类型,成员函数,成员变量,作为客户的模板代码可以通过traits模板类所公开的接口来间接访问之。花了点时间,憋了一个示例程序,虽然没什么实际意义,但对于理解traits来说,可能会有帮助。
#include
class CM {};
class CA {};
class CIM {};
template< typename T >
class Traits
{
public:
typedef unsigned int ValueType;
Traits() : m_rate( 2 ) {}
ValueType ComputeValue( ValueType value ) { return value * m_rate; }
private:
ValueType m_rate;
};
template<>
class Traits< CM >
{
public:
typedef double ValueType;
Traits() : m_rate( 1.2 ) {}
ValueType ComputeValue( ValueType value ) { return value * m_rate; }
private:
ValueType m_rate;
};
template<>
class Traits< CA >
{
public:
typedef int ValueType;
Traits() : m_rate( -1 ) {}
ValueType ComputeValue( ValueType value ) { return value * m_rate; }
private:
ValueType m_rate;
};
template< typename T >
struct ValueCount
{
void result()
{
Traits< T > traits;
Traits< T >::ValueType value = static_cast< Traits< T >::ValueType >( 2 );
std::cout << traits.ComputeValue( value ) << std::endl;
}
};
int main()
{
ValueCount< CIM > cim;
cim.result();
ValueCount< CM > cm;
cm.result();
ValueCount< CA > ca;
ca.result();
return 0;
}
代码中的Tratis类对于CA和CM有显式的特化实现,其中ValueType类型和rate与默认的实现不同,在类ValueCount中,利用Tratis对不同类型用一个统一的接口符号处理。程序的运行结果是4,2.4,-2。(这是我的第一个模版程序J)
2.SGI STL
中的
__type_traits
在SGI实现版的STL中,为了获取高效率,提供了__type_traits,用来提取类的信息,比如类是否拥有trival的构造、析构、拷贝、赋值操作,然后跟据具体的信息,就可提供最有效率的操作。以下摘录cygwin的gcc3.3源码,有改动,在中。
struct __true_type {};
struct __false_type {};
template
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;
};
对于普通类来讲,为了安全起见,都认为它们拥有non-trival的构造、析构、拷贝、赋值函数,POD是指plain old data。接下来对C++的原生类型(bool,int, double之类)定义了显式的特化实现,以double为例:
template<> struct __type_traits {
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;
};
还有,对所有的原生指针来讲,它们的构造、析构等操作也是trival的,因此有:
template
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;
};
简化中copy的部分代码来说明对__type_traits的应用。
template
inline _Tp*
__copy_trivial(const _Tp* __first, const _Tp* __last, _Tp* __result)
{
memmove(__result, __first, sizeof(_Tp) * (__last - __first));
return __result + (__last - __first);
}
template
inline _Tp*
__copy_aux (_Tp* __first, _Tp* __last, _Tp* __result, __true_type)
{ return __copy_trivial(__first, __last, __result); }
template
inline _Tp*
__copy_aux (_Tp* __first, _Tp* __last, _Tp* __result, __false_type)
{ 另外处理; }
template
inline _OutputIter
copy (_InputIter __first, _InputIter __last, _OutputIter __result)
{
typedef typename iterator_traits<_InputIter>::value_type _ValueType;
typedef typename __type_traits<_ValueType>::has_trivial_assignment_operator _Trivial;
return __copy_aux(__first, __last, __result, _Trivial());
}
Copy函数利用__type_traits判断当前的value_type是否有trival的赋值操作,如果是,则产生类__true_type的实例,编译时选择__copy_trivial函数进行memmove,效率最高。如果是non-trival的赋值操作,则另作处理,效率自然低些。__true_type和__false_type之所以是类,就因为C++的函数重载是根据类型信息来的,不能依据参数值来判别。使用SGI STL时,可以为自己的类定义__type_traits显式特化版本,以求达到高效率。
3. STL
中的
iterator_traits
iterator_traits提供5个特性的提取,至于为什么是5个以及iterator的分类,以后再议。代码包含在中。
template
typename _Pointer = _Tp*, typename _Reference = _Tp&>
struct iterator
{
typedef _Category iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Pointer pointer;
typedef _Reference reference;
};
template
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;
};
原生指针(如int*,double*)也是iterator,但它不是类,无法提取出value_type,所以要对原生指针和const原生指针进行显式特化。
template
struct iterator_traits<_Tp*> {
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef _Tp* pointer;
typedef _Tp& reference;
};
template
struct iterator_traits {
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef const _Tp* pointer;
typedef const _Tp& reference;
};
现在,对于所有的iterator都可以正确的提取出以上5个特性。
下面解释iterator_category,iterator共分为5类,input_iterator,output_iterator,forward_iterator,bidirectional_iterator,random_access_iterator。其中forward_iterator是input_iterator和output_iterator的强化(refinement),bidirectional_iterator是forward_iterator的强化,random_access_iterator是bidirectional_iterator的强化。由于5种iterator的性质的同异,需要对它们的种类进行区分,制定特化的函数以达到最优的效率,就像上一节的type_traits一样。需要强调的是,强化不是继承,C++重载机制支持对继承类的正确选择。由于不同iterator有共同的操作,在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 {};
由iterator_category带来的效率优化,可由在内的两个函数看出,一个是用来计算两个iterator的距离__distance,一个是将iterator累进n次的__advance。列举__distance的代码如下,有改动。
template
inline typename iterator_traits<_InputIterator>::difference_type
__distance(_InputIterator __first, _InputIterator __last,
input_iterator_tag)
{
typename iterator_traits<_InputIterator>::difference_type __n = 0;
while (__first != __last) {
++__first; ++__n;
}
return __n;
}
template
inline typename iterator_traits<_RandomAccessIterator>::difference_type
__distance(_RandomAccessIterator __first, _RandomAccessIterator __last,
random_access_iterator_tag)
{ return __last - __first; }
template
inline typename iterator_traits<_Iter>::iterator_category
__iterator_category(const _Iter&)
{ return typename iterator_traits<_Iter>::iterator_category(); }
template
inline typename iterator_traits<_InputIterator>::difference_type
distance(_InputIterator __first, _InputIterator __last)
{ return __distance(__first, __last, __iterator_category(__first)); }
4.
traits
技术还有很夸张的应用。《
C++
设计新思维:范型编程与设计模式之应用》中有体现,或者,泛型编程还得依赖
traits
技术,也许以后的
C++
会从语言特性上支持
traits
。