C++編譯期的類型測試

編譯期的類型測試

一、使用模板特化機制

如比較兩個類型是否一致:

VC8及以後版本支持了type traits機制:

add_const Class            // Makes const type from type.

add_cv Class               // Makes const/volatile type from type.

add_pointer Class          // Makes pointer to type from type.

add_reference Class        // Makes reference to type from type.

add_volatile Class         // Makes volatile type from type.

aligned_storage Class      // Makes suitably aligned type.

alignment_of Class         // Gets alignment of type.

common_type Class

conditional Class

decay Class

enable_if Class

extent Class               // Gets an array dimension.

has_nothrow_assign Class   // Tests whether the type does not throw on assign.

has_nothrow_constructor Class // Tests whether the type does not throw on default construction.

has_nothrow_copy Class     // Tests whether the type does not throw on copy construction.

has_nothrow_copy_constructor Class

has_nothrow_default_constructor Class

has_trivial_assign Class   // Tests whether the type has trivial assign.

has_trivial_constructor Class // Tests whether the type has trivial default constructor.

has_trivial_copy Class     // Tests whether the type has trivial copy constructor.

has_trivial_copy_constructor Class

has_trivial_default_constructor Class

has_trivial_destructor Class // Tests whether the type has trivial destructor.

has_virtual_destructor Class // Tests whether the type has virtual destructor.

is_abstract Class          // Tests whether the type is abstract class.

is_arithmetic Class        // Tests whether the type is arithmetic.

is_array Class             // Tests whether the type is array.

is_base_of Class           // Tests whether one type is the base of another.

is_class Class             // Tests whether the type is a class.

is_compound Class          // Tests whether the type is not scalar.

is_const Class             // Tests whether the type is const.

is_convertible Class       // Tests whether one type is convertible to another.

is_empty Class             // Tests whether the type is an empty class.

is_enum Class              // Tests whether the type is an enumeration.

is_floating_point Class    // Tests whether the type is floating-point.

is_function Class          // Tests whether the type is a function type.

is_fundamental Class       // Tests whether the type is void or arithmetic.

is_integral Class          // Tests whether the type is integral.

is_lvalue_reference Class

is_member_function_pointer Class // Tests whether the type is a pointer to a member function.

is_member_object_pointer Class // Tests whether the type is a pointer to a member object.

is_member_pointer Class    // Tests whether the type is a pointer to a member.

is_object Class            // Tests whether the type is an object type.

is_pod Class               // Tests whether the type is a POD.

is_pointer Class           // Tests whether the type is a pointer.

is_polymorphic Class       // Tests whether the type has a virtual function.

is_reference Class         // Tests whether the type is a reference.

is_rvalue_reference Class

is_same Class              // Tests whether two types are the same.

is_scalar Class            // Tests whether the type is scalar.

is_signed Class            // Tests whether the type is a signed integer.

is_standard_layout Class

is_union Class             // Tests whether the type is a union.

is_unsigned Class          // Tests whether the type is an unsigned integer.

is_void Class              // Tests whether the type is void.

is_volatile Class          // Tests whether the type is volatile.

make_signed Class

make_unsigned Class

rank Class                 // Gets the number of array dimensions.

remove_all_extents Class   // Makes non-array type from array type.

remove_const Class         // Makes non-const type from type.

remove_cv Class            // Makes non-const/volatile type from type.

remove_extent Class        // Makes element type from array type.

remove_pointer Class       // Makes type from a pointer to type.

remove_reference Class     // Makes non-reference type from type.

remove_volatile Class      // Makes non-volatile type from type.

integral_constant Class    // Makes integral constant from type and value.

 

二、使用Traits Classes表現類型信息

STL中有個advance函數,它的作用是將某個迭代器向前或向後移動移動某個給定的距離。

template<class _InIt, class _Diff>
	void advance(_InIt& _Where, _Diff _Off)

這個函數就是執行 _Where += _Off 的動作但是實際上只有隨機訪問迭代器才支持+=操作,對於其他類型的迭代器只能反覆使用++或--操作,共_Off次。

因此,我們首先想到這樣處理:

template<class _InIt, class _Diff>
    void advance(_InIt& _Where, _Diff _Off)
{	
   if(_Where is a random access iterator)
   {
       _Where += _Off;  // 針對隨機訪問迭代器,使用+=運算
   }
   else // 對於其他類型迭代器,重複使用++或--
   {
       if(_Off >= 0) 
       {    while(_Off--) ++_Where;    }
       else
       {    while(_Off++) --_Where;    }
   }
}

迭代器是模板類,不同的類型模板其實就是一個不同的類型,如何確定迭代器類型呢?

STL通過Traits classes類表現迭代器的類型信息:

1、STL封裝的五種迭代器類型,對這五種類型使用卷標結構加以確認;

		// ITERATOR TAGS
struct input_iterator_tag
	{	// identifying tag for input iterators
	};
struct output_iterator_tag
	{	// identifying tag for output iterators
	};
struct forward_iterator_tag: public input_iterator_tag, output_iterator_tag
	{	// identifying tag for forward iterators
	};
struct bidirectional_iterator_tag: public forward_iterator_tag
	{	// identifying tag for bidirectional iterators
	};
struct random_access_iterator_tag: public bidirectional_iterator_tag
	{	// identifying tag for random-access iterators
	};

2、爲每個迭代器打上該類型標籤:

template<class _Myvec>
	class _Vector_iterator : public _Vector_const_iterator<_Myvec>
	{	// iterator for mutable vector
public:
	typedef random_access_iterator_tag iterator_category;
     };

template<class _Mylist>
	class _List_iterator : public _List_const_iterator<_Mylist>
	{	// iterator for mutable list
public:
	typedef bidirectional_iterator_tag iterator_category;
     };

因此,對於advance傳遞的迭代器,可以通過_InIt::iterator_category確認迭代器類型信息。然而僅僅如此並不能使advance對於傳遞的指針類型生效。

3、定義迭代器的Traits classes類,使advance能夠處理指針類型數據

		// TEMPLATE CLASS iterator_traits
template<class _Iter>
	struct iterator_traits
	{	// get traits from iterator _Iter
	typedef typename _Iter::iterator_category iterator_category;
	typedef typename _Iter::value_type value_type;
	typedef typename _Iter::difference_type difference_type;
	typedef difference_type distance_type;	// retained
	typedef typename _Iter::pointer pointer;
	typedef typename _Iter::reference reference;
	};
template<class _Ty>
	struct iterator_traits<_Ty *>
	{	// get traits from pointer
	typedef random_access_iterator_tag iterator_category;
	typedef _Ty value_type;
	typedef ptrdiff_t difference_type;
	typedef ptrdiff_t distance_type;	// retained
	typedef _Ty *pointer;
	typedef _Ty& reference;
	};

這樣,迭代器的類型信息就可以確定了,advance函數的處理僞代碼就可以這樣實現了:

template<class _InIt, class _Diff>
    void advance(_InIt& _Where, _Diff _Off)
{	
   if(typeid(std::iterator_traits<_InIt>::iterator_category)
       == typeid(std::random_access_iterator_tag))
   {
       _Where += _Off;
   }
   else
   {
       if(_Off >= 0) 
       {    while(_Off--) ++_Where;    }
       else
       {    while(_Off++) --_Where;    }
   }
}

然而,std::iterator_traits<_InIt>::iterator_category是可在編譯期確定的類型,使用if語句卻是在運行期確定。爲什麼將可以在編譯器完成的事情放在運行期呢?這樣既浪費執行時間也造成可執行文件的膨脹。

4、使用重載機制,實現編譯器的類型確定;

template<class _InIt, class _Diff> 
	void _Advance(_InIt& _Where, _Diff _Off, input_iterator_tag)
	{	// increment iterator by offset, input iterators
	for (; 0 < _Off; --_Off)    ++_Where;
	}

template<class _FI, class _Diff> 
	void _Advance(_FI& _Where, _Diff _Off, forward_iterator_tag)
	{	// increment iterator by offset, forward iterators
	for (; 0 < _Off; --_Off)    ++_Where;
	}

template<class _BI, class _Diff> 
	void _Advance(_BI& _Where, _Diff _Off, bidirectional_iterator_tag)
	{	// increment iterator by offset, bidirectional iterators
	for (; 0 < _Off; --_Off)    ++_Where;
	for (; _Off < 0; ++_Off)    --_Where;
	}

template<class _RI, class _Diff>
	void _Advance(_RI& _Where, _Diff _Off, random_access_iterator_tag)
	{	// increment iterator by offset, random-access iterators
	_Where += _Off;
	}

這樣,advance函數的實現就是這樣的了:

template<class _InIt, class _Diff>
void advance(_InIt& _Where, _Diff _Off)
{	
    _Advance(_Where, _Off, std::iterator_traits<_InIt>::iterator_category());
}

總結:

1)定義一系列的卷標結構,併爲一族類型指定(typedef)各卷標結構標識類型信息;

2)使用模板和模板特化技術定義Traits 類,使得“類型信息”在編譯器可用;

3)建立一組重載函數或函數模板(如_Advance),彼此間的差異只在於Traits參數。令每個函數的實現代碼與其接受的Traits信息相對應, 實現了編譯期的類型檢查;

4)建立一個控制函數或函數模板(如advance),它調用上述那些重載函數並傳遞Traits class所提供的信息。

 

附:這種“編寫基於模板的C++程序並在編譯期執行的過程”就叫模板元編程。它將工作從運行期轉移到編譯期,可大大降低執行程序的大小和內存需求,提高運行效率。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章