[TOC] >type_traits已经成为了c++11/14标准的一部分,头文件为,该库实现了c++无法完成的特征萃取机功能,是泛型和模板编程基础设施。 >为了方便查看结果,后面测试全部返回true。 # 概述 type_traits库提供一组特征类,可以在编译器确定类型或者说是元数据是否拥有某特征,是否支持原生数组,是否是证书,是否重载某运算符,检查是否同一类型,还有添加或移除const,volatitle等 # 元数据类型 ## 简单数据类型检查 - is_integral : 检查T是否为bool,char,int等整形 - is_floating_point : 检查T是否为浮点型 - is_void : 检查T是否为void类新型 ``` std:: cout << (std::is_integral::value) << "\n"; std::cout << (!std::is_integral::value) << "\n"; ``` ## 其他类型检查 - is_array - is_class - is_enum - is_union - is_pointer - is_function - is_lvalue_reference - is_rvalue_reference ``` std::cout << (std::is_array::value) << "\n"; std::cout << (std::is_class::value) << "\n"; std::cout << (std::is_class::value) << "\n"; std::cout << (std::is_pointer::value) << "\n"; std::cout << (std::is_function::value) << "\n"; std::cout << (std::is_lvalue_reference::value) << "\n"; std::cout << (std::is_rvalue_reference::value) << "\n"; ``` ## 成员指针检查 - is_member_opject_pointer : 成员变量指针 - is_menber_function_pointer : 成员函数指针 ``` class Demo { int x; double y; void z() {}; std::function f = std::bind(&Demo::z,this); }; std::cout << (std::is_member_object_pointer::value) << "\n"; std::cout << (std::is_member_object_pointer < std::function Demo::*>::value) << "\n"; std::cout << (std::is_member_function_pointer::value) << "\n"; ``` ## 复合类型检查 - is_reference : 左右引用 - is_arithmetic : 算术类型(is_integral||is_float_pointer) - is_fundamental : 基本类型(is_arithmetic || is_void) - is_compound : 复合类型(!is_fundamental),std::string是复合类型 - is_member_pointer : 成员函数或成员变量 - is_scalar : 标量类型,算数类型,枚举,指针,成员指针 - is_object 实体对象类型,引用,void和函数之外 # 元数据属性 ## 基本修饰词 - is_const - is_volatile - is_signed - is_unsigned ## 数组属性 - rank : 如果是数组,返回维度,否则返回0 - extent : 如果是数组,返回第N维度的值,否则返回0 ``` std::cout << (std::rank::value == 2) << "\n"; std::cout << (std::extent::value == 3) << "\n"; ``` ## 类相关属性 - is_pod : 是否为POD类型,is_fundamental::value==true成立的都是POD类型,复合类型的POD没有构造函数,虚构函数,虚函数,内存是连续的 - is_empty : 空类 - is_abstract : 抽象类(纯虚函数) - is_polymorphic : 多态类(虚函数) - is_final : final类 ## 操作符重载属性 - has_greater : 重载operator> - has_less - has_equal_to - has_plus : operator+ - has_minus - has_pre_increment : operator++ # 元数据关系检查 - is_same : 是否相同 - is_convertible : 是否能隐式转换 - is_base_of : B是D基类或者相同 - is_virtual_base_of : B是D虚基类,非c++11/14标准 # 元数据运算 添加和删除各种修饰符,输入一个类型,输出一个新的类型type,可以随意处理c++类型 ## 元数据“加法” - add_const : 返回T const - add_volatile : 返回T volatile - add_cv : 返回T const volatile - add_pointer : 返回T* - add_lvalue_reference : 对象或者函数类型返回左值引用,通常是T&,否则是T - add_lvalue_reference : 对象和函数返回右值引用,通常T&&,否则T ``` typedef std::add_const::type md1; std::cout << (std::is_same::value) << "\n"; typedef std::add_volatile::type md2; std::cout << (std::is_same::value) << "\n"; typedef std::add_pointer::type md3; std::cout << (std::is_same::value) << "\n"; typedef std::add_lvalue_reference::type md4; std::cout << (std::is_same::value) << "\n"; typedef std::add_rvalue_reference::type md5; std::cout << (std::is_void::value) << "\n"; ``` # 元数据“删除” - remove_const - remove_volatile - remove_cv - remove_pointer - remove_reference ``` typedef int const **& rmd1; typedef std::remove_pointer::type rmd2; std::cout << (std::is_same::value) << "\n"; //该变量是双指针引用,需要先移除引用 typedef std::remove_reference::type rmd3; std::cout << (std::is_same::value) << "\n"; typedef std::remove_pointer::type>::type rmd4; std::cout << (std::is_same::value) << "\n"; typedef std::remove_const::type rmd5; std::cout << (std::is_same::value) << "\n"; ``` ## 处理算术类型 - make_signed : 返回T的有符号证书类型,cv修饰不变 - make_unsigned ## 处理数组类型 - remove_extend : 删除最高层维度 - remove_all_extents : 删除所有维度,返回0维普通类型 ``` typedef std::remove_extent::type re1; std::cout << (std::is_same::value) << "\n"; typedef std::remove_all_extents::type re2; std::cout << (std::is_same::value) << "\n"; ``` ## “?:”和共同类型 - conditional : 类似于“?:”,类似于mpl::if_C - common_type : 求多个类型的公共类型(类似于数字的最小公倍数) ``` typedef std::common_type::type ct1; std::cout << (std::is_same::value) << "\n"; typedef std::common_type::type ct2; std::cout << (std::is_same::value) << "\n"; //typedef std::common_type::type ct3;//编译错误 ``` # 实现原理 ## inregral_constant 很多值元函数都是用了元函数转发技术,把元参数转发给integral_constant计算,该类也是很多类的的public基类。 源码: ``` template struct integral_constant { static const T value = val; typedef T value_type; typedef integral_constant type; constexpr operator value_type() const _NOEXCEPT { return (value); } constexpr value_type operator()() const _NOEXCEPT { return(value); } }; ``` type_traits库中提供了以下两个针对bool元数据特化的无参元函数true_type和false_type,看起来像SGI stl中实现的__true_type和__false_type: ``` typedef integral_constant true_type; typedef integral_constant false_type; ``` ## is_integral `is_integral`使用了模板特化技术,对非整数的类型元函数的::value返回false,否则特化地返回true,代码如下: ``` template struct is_integral :public false_type {}; template<> struct is_integral :public true_type {}; template<> struct is_integral :public true_type {}; template<> struct is_integral :public true_type {}; template<> struct is_integral :public true_type {}; ``` ## is_same的实现 ``` template struct myis_same :public false_type {}; template struct myis_same :public true_type {}; ``` ## is_void实现 ``` template struct is_void : is_same::type> {}; ``` ## is_float_pointer实现 ``` template struct is_floating_point : integral_constant::type>::value || is_same::type>::value || is_same::type>::value)>{}; ``` ## is_array实现 ``` template struct is_array :public false_type {}; template struct is_array :public true_type {}; template struct is_array :public true_type {}; ``` ## is_pointer实现 ``` template struct is_pointer_helper :public false_type {}; template struct is_pointer_helper :public true_type {}; template struct is_pointer :public is_pointer_helper::type> {}; ``` ## is_member_pointer实现 ``` template struct is_member_pointer_helper :public false_type {}; template struct is_member_pointer_helper :public true_type {}; template struct is_member_pointer :public is_member_pointer_helper::type> {}; ``` 测试: ``` std::cout << (expr::is_member_pointer::value ? "is member pointer\n" : "is not member pointer\n"); std::cout << (expr::is_member_pointer::value ? "is member pointer\n" : "is not member pointer\n"); 输出: is member pointer is member pointer ``` > 并不是判断类T中是否真的有返回值为int的函数,或者是否有int型变量,而是只是判断T这个写法是否是成员函数指针、指向成员变量指针类型。 ## is_class实现 ``` template char check(int T::*) {}; //T是class,struct,返回一个大小的char struct two { char c[2]; }; template two check(...) {}; //T是非class ,struct返回两个大小的char //is_union,排除union体 template struct is_class :public integral_constant(0)) == 1 && !std::is_union::value>{}; ``` ## is_base_of实现 ``` template::value && is_class::value)> class is_base_of { template static char helper(Derived, T) {}; static int helper(Based, int) {}; struct Conv { operator Derived(); operator Based() const; }; public: static const bool value = sizeof(helper(Conv(),0)) == 1; }; template class is_base_of { public: static const bool value = is_same::value; }; ``` - operator Devied() 是类型转换操作符,将类类型值转变为其他类型值的转换,在保留字 operator 之后跟着转换的目标类型,详细参考类型强制转换成员函数; - 当 Base 不是Devied 的超类时,那 operator Devied() 和 operator Base() const 则不是重载关系了;接下来,两个函数类型转换函数都可以匹配 helper(Conv(), 0) ,因为 operator Devied() 满足 static char helper(Devied, T); operator Base() const 满足 static int helper(Base, int);但是由于优先匹配非模板的函数的规则,在这里会匹配 static int helper(Base, int);Conv()会转换成Base,helper(Conv(), 0) 返回的类型是int,最后 sizeof(int) != 1 。 - 当 Base 是Devied 的超类时,那 operator Devied() 和 operator Base() const 则是重载 关系。那由于 Conv() 不是const类型,只能调用 operator Devied() 做类型转换,最后只能匹配 static char helper(Devied, T); 返回的类型是char,最后 sizeof(char) == 1 。 参考1:[C++ is_base_of](https://www.jianshu.com/p/ad9f900d0c47) 参考2:[【C++11学习笔记】类型判断的type_traits学习](https://www.cnblogs.com/xellosscao/p/6411312.html)