为了方便查看结果,后面测试全部返回true。
概述
type_traits库提供一组特征类,可以在编译器确定类型或者说是元数据是否拥有某特征,是否支持原生数组,是否是证书,是否重载某运算符,检查是否同一类型,还有添加或移除const,volatitle等
元数据类型
简单数据类型检查
is_integral : 检查T是否为bool,char,int等整形
is_floating_point : 检查T是否为浮点型
is_void : 检查T是否为void类新型
std:: cout << (std::is_integral<const char>::value) << "\n";
std::cout << (!std::is_integral<void*>::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<int[]>::value) << "\n";
std::cout << (std::is_class<std::string>::value) << "\n";
std::cout << (std::is_class<class Demo>::value) << "\n";
std::cout << (std::is_pointer<int*>::value) << "\n";
std::cout << (std::is_function<void(int)>::value) << "\n";
std::cout << (std::is_lvalue_reference<float&>::value) << "\n";
std::cout << (std::is_rvalue_reference<float&&>::value) << "\n";
成员指针检查
- is_member_opject_pointer : 成员变量指针
- is_menber_function_pointer : 成员函数指针
class Demo
{
int x;
double y;
void z() {};
std::function<void()> f = std::bind(&Demo::z,this);
};
std::cout << (std::is_member_object_pointer<int Demo::*>::value) << "\n";
std::cout << (std::is_member_object_pointer < std::function<void()> Demo::*>::value) << "\n";
std::cout << (std::is_member_function_pointer<void(Demo::*)()>::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<int[2][3]>::value == 2) << "\n";
std::cout << (std::extent<int[2][3], 1>::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<int>::type md1;
std::cout << (std::is_same<md1, int const>::value) << "\n";
typedef std::add_volatile<int const>::type md2;
std::cout << (std::is_same<md2, int const volatile>::value) << "\n";
typedef std::add_pointer<int>::type md3;
std::cout << (std::is_same<md3, int *>::value) << "\n";
typedef std::add_lvalue_reference<md3>::type md4;
std::cout << (std::is_same<md4, int *&>::value) << "\n";
typedef std::add_rvalue_reference<void>::type md5;
std::cout << (std::is_void<md5>::value) << "\n";
元数据“删除”
- remove_const
- remove_volatile
- remove_cv
- remove_pointer
- remove_reference
typedef int const **& rmd1;
typedef std::remove_pointer<rmd1>::type rmd2;
std::cout << (std::is_same<rmd1, rmd2>::value) << "\n"; //该变量是双指针引用,需要先移除引用
typedef std::remove_reference<rmd2>::type rmd3;
std::cout << (std::is_same<rmd3, int const **>::value) << "\n";
typedef std::remove_pointer<std::remove_pointer<rmd3>::type>::type rmd4;
std::cout << (std::is_same<rmd4, int const>::value) << "\n";
typedef std::remove_const<rmd4>::type rmd5;
std::cout << (std::is_same<rmd5, int>::value) << "\n";
处理算术类型
- make_signed : 返回T的有符号证书类型,cv修饰不变
- make_unsigned
处理数组类型
- remove_extend : 删除最高层维度
- remove_all_extents : 删除所有维度,返回0维普通类型
typedef std::remove_extent<int[1][2][5][7]>::type re1;
std::cout << (std::is_same<re1, int[2][5][7]>::value) << "\n";
typedef std::remove_all_extents<int[1][5][7]>::type re2;
std::cout << (std::is_same<re2, int>::value) << "\n";
“?:”和共同类型
- conditional : 类似于“?:”,类似于mpl::if_C
- common_type : 求多个类型的公共类型(类似于数字的最小公倍数)
typedef std::common_type<int, char>::type ct1;
std::cout << (std::is_same<ct1, int>::value) << "\n";
typedef std::common_type<int, double>::type ct2;
std::cout << (std::is_same<ct2, double>::value) << "\n";
//typedef std::common_type<int, std::string>::type ct3;//编译错误
实现原理
inregral_constant
很多值元函数都是用了元函数转发技术,把元参数转发给integral_constant计算,该类也是很多类的的public基类。
源码:
template<typename T, T val>
struct integral_constant
{
static const T value = val;
typedef T value_type;
typedef integral_constant<T, val> 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<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
is_integral
is_integral使用了模板特化技术,对非整数的类型元函数的::value返回false,否则特化地返回true,代码如下:
template<typename T> struct is_integral :public false_type {};
template<> struct is_integral<bool> :public true_type {};
template<> struct is_integral<char> :public true_type {};
template<> struct is_integral<unsigned int> :public true_type {};
template<> struct is_integral<signed int> :public true_type {};
is_same的实现
template<typename T, typename U> struct myis_same :public false_type {};
template<typename T> struct myis_same<T,T> :public true_type {};
is_void实现
template<typename T> struct is_void : is_same<void, typename std::remove_cv<T>::type> {};
is_float_pointer实现
template<typename T >
struct is_floating_point : integral_constant<bool, (is_same<float, typename std::remove_cv<T>::type>::value
|| is_same<double, typename std::remove_cv<T>::type>::value
|| is_same<long double, typename std::remove_cv<T>::type>::value)>{};
is_array实现
template<typename T> struct is_array :public false_type {};
template<typename T> struct is_array<T[]> :public true_type {};
template<typename T,std::size_t N> struct is_array<T[N]> :public true_type {};
is_pointer实现
template<typename T> struct is_pointer_helper :public false_type {};
template<typename T> struct is_pointer_helper<T*> :public true_type {};
template<typename T> struct is_pointer :public is_pointer_helper<typename std::remove_cv<T>::type> {};
is_member_pointer实现
template<typename T> struct is_member_pointer_helper :public false_type {};
template<typename T,class U> struct is_member_pointer_helper<T (U::*)> :public true_type {};
template<typename T> struct is_member_pointer :public is_member_pointer_helper<typename std::remove_cv<T>::type> {};
测试:
std::cout << (expr::is_member_pointer<int demo1::*>::value ? "is member pointer\n" : "is not member pointer\n");
std::cout << (expr::is_member_pointer<int(demo2::*)>::value ? "is member pointer\n" : "is not member pointer\n");
输出:
is member pointer
is member pointer
并不是判断类T中是否真的有返回值为int的函数,或者是否有int型变量,而是只是判断T这个写法是否是成员函数指针、指向成员变量指针类型。
is_class实现
template<typename T> char check(int T::*) {}; //T是class,struct,返回一个大小的char
struct two { char c[2]; };
template<typename T> two check(...) {}; //T是非class ,struct返回两个大小的char
//is_union,排除union体
template<typename T> struct is_class :public integral_constant<bool, sizeof(check<T>(0)) == 1 && !std::is_union<T>::value>{};
is_base_of实现
template<typename Based,typename Derived,bool = (is_class<Based>::value && is_class<Derived>::value)>
class is_base_of
{
template<typename T>
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<typename Based,typename Derived>
class is_base_of<Based,Derived,false>
{
public:
static const bool value = is_same<Based, Derived>::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 。