C++编译期的类型测试

来源:互联网 发布:超级舰队老僧扫矿软件 编辑:程序博客网 时间:2024/04/30 00:56

编译期的类型测试

一、使用模板特化机制

如比较两个类型是否一致:

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 TAGSstruct 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 vectorpublic:typedef random_access_iterator_tag iterator_category;     };template<class _Mylist>class _List_iterator : public _List_const_iterator<_Mylist>{// iterator for mutable listpublic:typedef bidirectional_iterator_tag iterator_category;     };

因此,对于advance传递的迭代器,可以通过_InIt::iterator_category确认迭代器类型信息。然而仅仅如此并不能使advance对于传递的指针类型生效。

3、定义迭代器的Traits classes类,使advance能够处理指针类型数据

// TEMPLATE CLASS iterator_traitstemplate<class _Iter>struct iterator_traits{// get traits from iterator _Itertypedef 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;// retainedtypedef typename _Iter::pointer pointer;typedef typename _Iter::reference reference;};template<class _Ty>struct iterator_traits<_Ty *>{// get traits from pointertypedef random_access_iterator_tag iterator_category;typedef _Ty value_type;typedef ptrdiff_t difference_type;typedef ptrdiff_t distance_type;// retainedtypedef _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 iteratorsfor (; 0 < _Off; --_Off)    ++_Where;}template<class _FI, class _Diff> void _Advance(_FI& _Where, _Diff _Off, forward_iterator_tag){// increment iterator by offset, forward iteratorsfor (; 0 < _Off; --_Off)    ++_Where;}template<class _BI, class _Diff> void _Advance(_BI& _Where, _Diff _Off, bidirectional_iterator_tag){// increment iterator by offset, bidirectional iteratorsfor (; 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++程序并在编译期执行的过程”就叫模板元编程。它将工作从运行期转移到编译期,可大大降低执行程序的大小和内存需求,提高运行效率。

0 0
原创粉丝点击