!!! C++11/14 Boost探秘--类型特征萃取

为了方便查看结果,后面测试全部返回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 。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值