C++类型萃取
- 1. 功能
- 2. 应用场景
- 3. 实现
- 4. 代码
1. 功能
类型萃取,可以在模板中萃取到变量类型,对不同变量进行不同处理,可以提升程序效率.
也就是我根据你传递过来的类型,我再决定调用那种方法
在STL中用到的比较多,用于判断一个变量是否为POD类型.
简述来说可以用来判断出某个变量是内置类型还是自定义类型.
2. 应用场景
比如我们实现顺序表,在对顺序表进行扩容时,就靠重新开辟内存、拷贝对象.
拷贝对象时,就有两种情况:一种是类型,比如int char…;还有一种是自定义类型,Data类、String类.
对于内置类型,我们可以通过
memset
,来进行赋值.(扩展,浅拷贝相关的类也可以通过
memset
赋值)
而对于自定义类型,大多数深拷贝的对象来说,我们必须通过调用赋值语句来赋值.
因此,我们通常在拷贝对象时,为了不出现错误,都用赋值语句来赋值.
而我们如果有一种方法/机制可以判断POD类型或者非POD类型.
对于POD类型用
memset
函数,对于非POD用赋值,这样就能提高程序的效率
3. 实现
从顺序表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
为非内置类型时就走的是另外的方法,这就是类型萃取思想。
4. 代码
类型萃取:
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();
}