c++:模板的类型萃取
来源:互联网 发布:2k显示器有必要吗 知乎 编辑:程序博客网 时间:2024/05/16 19:36
首先我们通过一个模板类的顺序表,来了解c++在什么情况下需要对不同的类型不同对待。
这里为了说明重点,只写了增容和尾插部分。
template <class T>class SeqList{public: SeqList() :_a(NULL) , _size(0) , _capacity(0) {} void CheckCapacity() { if (_size >= _capacity) { _capacity = _capacity > 0 ? _capacity * 2 : 3;//当容量为0时增容为3,之后每次增2倍 T* newA = new T[_capacity]; if (_a != NULL) { memcpy(newA, _a, _size*sizeof(T));//使用内置类型:memcpy } delete[] _a; _a = newA; } } void PushBack(const T& x) { CheckCapacity(); _a[_size++] = x; } void Print() { for (size_t i = 0; i < _size; i++) { cout << _a[i] << " "; } cout << endl; }private: T* _a; size_t _size; size_t _capacity;};void TestSeqList(){ SeqList<int> s1; s1.PushBack(1); s1.PushBack(2); s1.PushBack(3); s1.PushBack(4); s1.Print();}int main(){ TestSeqList(); return 0;}
成功实现尾插四个数字:
可是如果我们在测试代码里存string类型,会不会依旧测试成功?
void TestSeqList(){ SeqList<string> s2; s2.PushBack("1"); s2.PushBack("2"); s2.PushBack("3"); s2.PushBack("4"); s1.Print();}
这种情况运行不能通过。
为什么呢?
因为这里用的是memcpy,所以新开辟的空间的前三个_str和_a指向的空间的每一个_str指向的一样。
这样就导致delete[] _a的时候,新开辟的空间的前三个_str为野指针,从而运行不能通过。
其实可以通过全特化来解决这个问题,但因为这样做会让代码的复用性很差,全是重复代码,所以不提倡使用。
还有一种方法是利用operator=,通过for循环依次赋值,这样新旧_str指向的空间不同,解决问题。
for (size_t i = 0; i < _size; i++) { newA[i] = _a[i];}
这里提到了全特化
来通过一个例子了解一下:
template<typename T1,typename T2>//全特化class Data{public: Data() { cout<<"Data(T1,T2)"<<endl; }private: T1 _d1; T2 _d2;};template<>class Data<int,char>{public: Data() { cout<<"Data(int, char)"<<endl; }private: int _d1; char _d2;};//template<class T1> //偏特化//class Data<T1,double>//{//public:// Data()// {// cout<<"Data(T1, double)"<<endl;// }//private:// T1 _d1;// double _d3;//};int main(){ Data<int,int>d1; Data<int,char>d2; return 0;}
我们知道一般的类型(比如int,float,double,char等)进行复制的时候采用memcpy效率会高一些;而像string或者是其他的一些自定义类型,继续用mencpy将出现错误,采用for循环进行一个一个复制(赋值运算符重载)才是正确的方法。
但是采用for循环拷贝效率明显不如memcpy函数高,如何才能让程序在运行内置类型时调用memcpy,而拷贝自定义类型时防止错误调用for循环拷贝,两者兼顾呢??
这里就用到了我们今天的主角:
类型萃取
下面是一个简单的类模板
template<class _TP>class Type{};
在一个这个类中加入一个内嵌类型,这样就可以知道是用户自定义类型还是内置类型。
template< >struct TypeTraits<int>{ typedef __TrueType IsPodType;//内嵌重定义};
template<class _TP>struct TypeTraits{ typedef __FalseType IsPodType;};
在这里,__IsPodType叫做内嵌型别。
PoD:plain old date平凡类型
当遇到自定义类型时,就将__IsPodType定义为__TrueType;
当遇到非自定义类型时,就将__IsPodType定义为__FalseType;
来实现一个例子:
#include<iostream>using namespace std;struct __TrueType{ bool Get() { return true; }};struct __FalseType{ bool Get() { return false; }};template <class T>struct __TypeTraits{ typedef __FalseType IsPodType; //默认为不是基本类型 POD(基本类型)};template <>struct __TypeTraits<int>{ typedef __TrueType IsPodType; //int是基本类型};template <class T>T* TypeCopy(T* dst, const T* src, size_t n){ return __TypeCopy(dst, src, n, __TypeTraits<T>::IsPodType());}template <class T>T* __TypeCopy(T* dst, const T* src, size_t n,__TrueType){ cout << "memcpy()" << endl; return (T*)memcpy(dst, src, n*sizeof(T));}template <class T>T* __TypeCopy(T* dst, const T* src, size_t n, __FalseType){ for (size_t i = 0; i < n; i++) { dst[i] = src[i]; } cout << "for operator=()" << endl; return dst;}void TestSeqList(){ string s1[3]={"11","22","33"}; string s2[3]={"0","0","0"}; TypeCopy(s1,s2,3); int a1[3]={1,2,3}; int a2[3]={0,0,0}; TypeCopy(a1,a2,3);}int main(){ TestSeqList(); return 0;}
看起来是不是有点懵逼,来个过程解析图理清思路
- c++:模板的类型萃取
- c++:模板的类型萃取
- 模板的类型萃取
- 模板的类型萃取
- 模板的类型萃取
- 模板的类型萃取
- 模板的类型萃取
- C++模板类的类型萃取技术
- 类型萃取&类的模板特化
- C++_模板类与类型萃取技术
- c++::关于类型萃取
- 【C++】类型萃取
- 【C++】类型萃取
- C++ 模板类型萃取技术 第二部分 基于泛型的类型萃取技术
- C++ 模板类型萃取技术
- 类型的萃取
- POD类型的萃取
- 模板的特化和萃取
- POJ1351:Number of Locks(记忆化搜索)
- HttpServletRequest和response的模拟单元测试
- 【ML学习笔记】6:机器学习中的数学基础6(对角矩阵,对称矩阵,正交矩阵,特征分解)
- XML布局注意案例
- Hibernate聚合函数的使用
- c++:模板的类型萃取
- Art 相关文件结构
- python 字典
- 数组的基本操作
- 1038. 统计同成绩学生(20)--Python
- 1118关于C语言中内存计算,和一些运算符以及scanf和printf运行机制
- 观察者设计模式
- python安装的模块找不到
- python 集合