天天看点

C++类型萃取1. 功能2. 应用场景3. 实现4. 代码

C++类型萃取

  • 1. 功能
  • 2. 应用场景
  • 3. 实现
  • 4. 代码

1. 功能

  类型萃取,可以在模板中萃取到变量类型,对不同变量进行不同处理,可以提升程序效率.

  也就是我根据你传递过来的类型,我再决定调用那种方法

  在STL中用到的比较多,用于判断一个变量是否为POD类型.

  简述来说可以用来判断出某个变量是内置类型还是自定义类型.

C++类型萃取1. 功能2. 应用场景3. 实现4. 代码

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

的方

法。下面看看这些代码的调用理解图:

C++类型萃取1. 功能2. 应用场景3. 实现4. 代码

默认的

_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();
}