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++程序并在编译期执行的过程”就叫模板元编程。它将工作从运行期转移到编译期,可大大降低执行程序的大小和内存需求,提高运行效率。
- C++编译期的类型测试
- 编译期断言测试
- 编译期确定类型关系
- 编译期类型计算示例
- C语言的编译期行为(三) #的妙用
- C语言的编译期行为(前言)
- 编译期的优化
- 确定类型和表达式在编译期信息的模板技术
- C 使用宏 编译期 二进制表示
- 编译期判断类型之间是否可以convert
- C语言的编译期行为(一) defined预处理函数
- C语言的编译期行为(二) #error预处理器指令
- 了解隐式接口和编译期的多态(Effective C++_41)
- C/C++可变参数宏, 编译期获取宏的可变参数长度
- Loki库读解 STATIC_CHECK扩展:可放在任何地方的STATIC_CHECK,编译期打印出类型的大小
- 16种C语言编译警告(Warning)类型的解决方法
- 运行期绑定与编译期绑定的区别
- c++有关编译期和运行期的访问
- arm处理器分类
- Java解惑八:更多库之谜
- 罗梓通的课程设计
- spring Bean范围
- linux下默认的函数库和头文件路径
- C++编译期的类型测试
- 读mybatis源码之七:执行器Exceutor之四大执行器
- 洛书
- 【程序员编程艺术】第五章:寻找满足和为定值的两个或多个数
- gcc 的简易用法 (编译、参数与链结)
- 【Git】git reset (repo->index) git checkout (index->work)
- php zendstudio+wampserver的调试
- HTML5 CSS3 专题 :诱人的实例 3D旋转木马效果相册
- CMake 简介