类型萃取

在编程中我们可能时常会听到类型萃取这个高大上的"学术名词",我们今天来探究一下这个高大上的学术名词
到底是何方神圣,先看看官方的解释类型萃取使用模板技术来萃取类型(包含自定义类型和内置类型)的某些特
性,用以判断该类型是否含有某些特性,从而在泛型算法中来对该类型进行特殊的处理用来提高效率或者其他。
例如:在STL中的destory算法根据函数的参数类型的特性:是否有trivial destructor来选择对应的策略来进行
destory,如果为内置类型,则不调用该类型的destructor,否则对迭代器范围内的对象调用destructor来进行
destory。
类型萃取的意思其实一点都不难,就是兵来将挡,水来土掩的意思,也就是我根据你传递过来的类型,我再决定
调用那种方法.举个例子吧,当你在使用STL的顺序表的时,当类型为内置类型的时候系统程序使用realloc开辟
空间很有效率,当时当类型为自定义类型时,用realloc显然不可以的,这个时候又用new的方式来。
首先我们应该明白,类型萃取原理是什么??它是依据什么来实现的??

特化==>

类型萃取依靠的就是 模板的特化  
模板特化分为两种: 全特化和偏特化
模板为什么要特化?
因为编译器认为,对于特定的类型,如果你能对某一功能更好的实现,那么就该听你的。
今天我简单认识一下特化怎么使用就好,这个我会有一个博客专门写:
现在我们介绍一下全特化: 
看下面的例子:
template<class T>
class A
{
public:A():a(0){}~A(){cout << "这里走了原始的模板"<< endl;}
protected:T a;
};template<>
class A<int>
{
public:A():a(0){}~A(){cout << "这里走了全特化后int的版本" << endl;}
protected:int a;
};void test2()
{A<char> a;A<int> b;
}
我们先看看程序运行的结果:
我们发现按照我们的意思解释这个就很通顺,a先实例化然后它后析构,b发生了全特化,所以它调用的
是int的模板版本。
下面是我调试时实例化b的时候,发生的事情,程序走的是int类型特化版本,有图有真相:
今天用的全特化就够用了,我们重点是理解类型萃取,好了既然我们了解到类型萃取的原理,现在我们看类型
萃取怎么使用的!

应用实例:

今天我就从顺序表SeqList这里入手:
注意这个顺序表是我们自己写的一个模板类,他现在有一个问题我们需要的是一个动态存储的顺序表,所以
这里会有一个扩容的情况,但是因为模板里面你接收到的类型千奇百怪,所以不可能你只有一种扩容方法,一
个是效率低,其次有的类型你用这种方法又不行,这时候就是类型萃取大展身手的时候了。在顺序表中,当你
使用内置类型时使用realloc扩容空间能好点,当你是自定义类型时你就得老老实实的使用别的方法了。
我先把扩容的那个函数拿出来:
void _CheckCapacity(){if (_size >= _capacity){if (TypeTraits <T>::__IsPODType().Get()){cout << "这里是内置类型扩容的情况" << endl;_a = (T*)realloc(_a, (_capacity * 2 + 3)*sizeof(T));_capacity = _capacity * 2 + 3;}else{if (_a == NULL){_a = new T[3];}cout << "这里是非内置类型扩容的情况" << endl;_capacity = _capacity * 2 + 3;T* tmp  = new T[_capacity];if (_a){for (size_t i = 0; i < _size; ++i){tmp[i] = _a[i];}delete[] _a;_a = tmp;}}}}
看到这里大家可能都会发现这里 if (TypeTraits <T>::__IsPODType().Get()) 这句其实是最关键的,用这句来区别调用
的是哪个方法。   但是这句里面的 __IsPODType()和Get()是哪里来的呢?
struct __TrueType
{bool Get(){return true;}
};struct __FalseType
{bool Get(){return false;}
};
这个是TypeTraits的模板本体,默认__IsPODType为_FalseType.当它为内置类型的特化时  __IsPODType为_TureType
template <class _Tp>
struct TypeTraits
{typedef __FalseType   __IsPODType;
};
//从这开始都是特化版本(类型萃取的开始)
template <>
struct TypeTraits< char>
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< unsigned char >
{typedef __TrueType     __IsPODType;
};
为了类型萃取,我们把所有的内置类型进行特化, 当然这里我只是把内置类型特化的前两个拿了出来,当T为内置
类型 时 让 _IsPODType为_TureType,所以 if (TypeTraits <T>::__IsPODType().Get())表达为真,走的是realloc的方
法。下面看看这些代码的调用理解图:
默认的_TureType为 _FalseType,所以当T为非内置类型时就走的是另外的方法,这就是类型萃取思想,有木有觉得
突然不够高大上了呢。。  虽然它可能不是多么的难,但是我们不能够否认它的实用性和可操作性。
最关键的地方既然我们已经理解了,那么我把代码贴出来,大家根据代码再自己理解一下:
//***********************************************************************************************************//类型萃取
//***********************************************************************************************************//
struct __TrueType
{bool Get(){return true;}
};struct __FalseType
{bool Get(){return false;}
};template <class _Tp>
struct TypeTraits
{typedef __FalseType   __IsPODType;
};template <>
struct TypeTraits< char>
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< unsigned char >
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< bool>
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< short>
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< unsigned short >
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< int>
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< unsigned int >
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< long>
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< unsigned long >
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< long long >
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< unsigned long long>
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< float>
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< double>
{typedef __TrueType     __IsPODType;
};template <>
struct TypeTraits< long double >
{typedef __TrueType     __IsPODType;
};template <class _Tp>
struct TypeTraits< _Tp*>
{typedef __TrueType     __IsPODType;
};typedef int DataType;
template <class T>
class SeqList
{
public:SeqList():_a(NULL), _capacity(0), _size(0){}SeqList(const SeqList<T>& s){_a = new T[s._size];memcpy(_a, s._a, sizeof(T)*s._size);_size = s._size;_capacity = s._size;}SeqList<T>& operator= (SeqList<T> s){swap(_size, s._size);swap(_capacity, s._capacity);swap(_a, s._a);return *this;}~SeqList(){if (TypeTraits <T>::__IsPODType().Get()){free(_a);_capacity = _size = 0;}else{delete[] _a;_capacity = _size = 0;}}void PushBack(const T& x){_CheckCapacity();_a[_size] = x;++_size;}void PopBack(){if (_size > 0)--_size;}T& Back(){assert(_size > 0);return _a[_size - 1];}size_t Size(){return _size;}bool Empty(){return _size == 0;}void Print();void _CheckCapacity(){if (_size >= _capacity){if (TypeTraits <T>::__IsPODType().Get()){cout << "这里是内置类型扩容的情况" << endl;_a = (T*)realloc(_a, (_capacity * 2 + 3)*sizeof(T));_capacity = _capacity * 2 + 3;}else{if (_a == NULL){_a = new T[3];}cout << "这里是非内置类型扩容的情况" << endl;_capacity = _capacity * 2 + 3;T* tmp  = new T[_capacity];if (_a){for (size_t i = 0; i < _size; ++i){tmp[i] = _a[i];}delete[] _a;_a = tmp;}}}}
protected:T* _a;size_t _size;size_t _capacity;
};
template<class T>
void SeqList<T>::Print()
{for (size_t i = 0; i < _size; ++i){cout << _a[i] << " ";}cout << endl;
}void  Test()
{SeqList<int> a;a.PushBack(1);a.PushBack(2);a.PushBack(3);a.PushBack(9999999);a.Print();SeqList<string> b;b.PushBack("a");b.PushBack("b");b.PushBack("c");b.PushBack("zhangchenliang");b.Print();
}
现在我们再从调试的角度来看,程序的调用过程:
我的第一个断点打到需要扩容开始的地方:
现在走到这里,走进扩容函数:
因为开辟的是一个内置类型的空间,在if语句里程序跳转到了_TureTyped的Get()函数里面。
现在已经知道表达式为真,所以走的是if里面的开辟空间的方法。
这就是程序的基本运行过程,当模板参数为自定义类型时过程也是相似的,只不过最后走的是else里面的代码而已。
这就是一个最简单的类型萃取思想,你只要理解它在以后的各种各样的场合碰到,不同类型不同方法的时候能够 想到
类型萃取并灵活运用它,这就算你学会它了~ 它的思想很简单,就是兵来将挡,水来土掩。使用了类型萃取 让你代码
多一丝从容.(这里的特化一定要理解清楚,里面还有偏特化也很重要)。

C++ — 类型萃取相关推荐

  1. C++特化的应用——类型萃取

    提出问题:如何实现一个对于拷贝内置类型和自定义类型通用的拷贝函数? 1.拷贝内置类型 对于内置类型我们可以用memcpy进行拷贝,因为memcpy属于浅拷贝,内置类型不涉及资源管理的问题. 2.拷贝自 ...

  2. C/Cpp / STL / 类型萃取

    作用 类型萃取使用模板技术来萃取类型(包含自定义类型和内置类型)的某些特性,用以判断该类型是否含有某些特性,从而在泛型算法中来对该类型进行特殊的处理用来达到提高效率或者其他的目的. 类型萃取的实现的基 ...

  3. C++的类型萃取技术

    http://www.cppblog.com/nacci/archive/2005/11/03/911.aspx?spm=0.0.0.0.iyJqvt&file=911.aspx 自从C++中 ...

  4. C++之类型萃取技巧

    使用类型萃取的原因 就是当你的顺序表是自定义类型,我们进行顺序表增容的时候,这个时候会出现一个问题,比如string类型,这个类型中有一个_buf与_ptr,当储存少于16个的时候这时会储存在_buf ...

  5. C++类型萃取之type_traits和type_info

    类型萃取 类型判断 typeid decltype和declval enable_if 类型萃取 通过type_traits可以实现在编译期计算.查询.判断.转换和选择,增强了泛型编程的能力,也增强了 ...

  6. type_traits 类型萃取

    一. c++ traits traits是c++模板编程中使用的一种技术,主要功能: 把功能相同而参数不同的函数抽象出来,通过traits将不同的参数的相同属性提取出来,在函数中利用这些用traits ...

  7. C++ 模板类型萃取技术 traits

    当函数,类或者一些封装的通用算法中的某些部分会因为数据类型不同而导致处理或逻辑不同(而我们又不希望因为数据类型的差异而修改算法本身的封装时),traits会是一种很好的解决方案.(类型测试发生在编译期 ...

  8. [c++]——什么是类型萃取

    类型萃取 类型萃取从字面意思上来说其实就是帮助我们挑选某个对象的类型,筛选特定的对象来做特定的事. C++中的类型萃取并不是每个人都熟知,他们一般都出现在STL库底层的实现原理中,和笔者一样,相信听到 ...

  9. C++模板编程之类型萃取 惊鸿一瞥

    一.从模板函数std::distance(计算迭代器的距离)开始 #include <iostream> #include <vector> #include <list ...

最新文章

  1. 关于变量名前面加m的问题
  2. Java Comparator 珍藏版
  3. python【力扣LeetCode算法题库】104-二叉树的最大深度
  4. Android高通平台下编译时能生成(拷贝)预编译的so到system的lib目录
  5. 利用ASP.netCore自带DI(DependencyInjection)实现批量依赖注入
  6. 优点 spark_spark(一)
  7. java中udi_Java读取.properties配置文件的方法
  8. 微信小程序下拉刷新列表onPullDownRefresh;微信小程序上划加载列表onReachBottom;uni-app微信小程序下拉加载数据;uni-app微信小程序上划页面加载数据
  9. (王道408考研操作系统)第二章进程管理-第二节4:调度算法详解2(RR、HPF和MFQ)
  10. 【图像评价】基于matlab GUI图像质量评价【含Matlab源码 1373期】
  11. informix sybase数据库下载地址
  12. 海康威视SDKjava二次开发身份证人脸识别
  13. mac 打开虚拟机之后,原MAC没有声音解决方法
  14. 复现awvs——POODLE 攻击(带 CBC 密码套件的 SSLv3—CVE-2014-3566)
  15. android在framework层增加自己的service---仿照GPS
  16. 下载配置安装MySql---超详细教程
  17. java script的小基础
  18. 链塔智库|区块链产业要闻及动态周报(2021年8月第4周)
  19. 中国直接针对消费者的疾病风险和健康DNA测试行业市场供需与战略研究报告
  20. 鸿蒙音波萨顶顶,萨顶顶卸妆堪比整容,“神婆”变女神,网友:早就该这样!...

热门文章

  1. 前台开发技术那些事儿
  2. java ai库_百度AI开放平台 Java SDK
  3. javaweb(js)实现登录注册案例(一)
  4. VS2017 打包(详细)
  5. 北京络捷斯特第三方物流信息系统技术解析(三) 订单录入-出库订单
  6. Oracle中的视图和同义词
  7. 1.1 小白黑群晖构建,硬件推荐,硬件选购教程
  8. ACM算法之基础算法
  9. acegi过滤器介绍-未觉池塘青草梦,阶前梧叶已秋声-iteye技术网站
  10. 蓝牙 传输 socket