Traits技術
.概念
Trait的中文意思就是特性,Traits就像特性萃取機,榨取不同類的特性,以便能統一處理。Traits依靠顯式模板特殊化(explicit template specialization)來把代碼中因類型不同而發生變化的片斷拖出來,用統一的接口來包裝。這個接口可以包含一個C++類所能包含的任何東西:內嵌類型,成員函數,成員變量,作為客戶的模板代碼可以通過traits模板類所公開的接口來間接訪問之。花了點時間,憋了一個示例程序,雖然沒什么實際意義,但對于理解traits來說,可能會有幫助。
#include <iostream>
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源碼,有改動,在<type_traits.h>中。
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;
typedef __false_type is_POD_type;
};
對于普通類來講,為了安全起見,都認為它們擁有non-trival的構造、析構、拷貝、賦值函數,POD是指plain old data。接下來對C++的原生類型(bool,int, double之類)定義了顯式的特化實現,以double為例:
template<> struct __type_traits<long double> {
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 <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;
};
簡化<stl_algobase.h>中copy的部分代碼來說明對__type_traits的應用。
template<typename _Tp>
inline _Tp*
__copy_trivial(const _Tp* __first, const _Tp* __last, _Tp* __result)
{
memmove(__result, __first, sizeof(_Tp) * (__last - __first));
return __result + (__last - __first);
}
template<typename _Tp>
inline _Tp*
__copy_aux (_Tp* __first, _Tp* __last, _Tp* __result, __true_type)
{ return __copy_trivial(__first, __last, __result); }
template<typename _Tp>
inline _Tp*
__copy_aux (_Tp* __first, _Tp* __last, _Tp* __result, __false_type)
{ 另外處理; }
template<typename _InputIter, typename _OutputIter>
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的分類,以后再議。代碼包含在<stl_iterator_base_types.h>中。
template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t,
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<typename _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;
};
原生指針(如int*,double*)也是iterator,但它不是類,無法提取出value_type,所以要對原生指針和const原生指針進行顯式特化。
template<typename _Tp>
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<typename _Tp>
struct iterator_traits<const _Tp*> {
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帶來的效率優化,可由在<stl_iterator_base_funcs.h>內的兩個函數看出,一個是用來計算兩個iterator的距離__distance,一個是將iterator累進n次的__advance。列舉__distance的代碼如下,有改動。
template<typename _InputIterator>
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<typename _RandomAccessIterator>
inline typename iterator_traits<_RandomAccessIterator>::difference_type
__distance(_RandomAccessIterator __first, _RandomAccessIterator __last,
random_access_iterator_tag)
{ return __last - __first; }
template<typename _Iter>
inline typename iterator_traits<_Iter>::iterator_category
__iterator_category(const _Iter&)
{ return typename iterator_traits<_Iter>::iterator_category(); }
template<typename _InputIterator>
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。
posted on 2008-11-08 22:48 肥仔 閱讀(2346) 評論(0) 編輯 收藏 引用 所屬分類: C++ 模板