C++ 模板 之 类型萃取 与 容器适配器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 模板 之 类型萃取 与 容器适配器相关的知识,希望对你有一定的参考价值。


类型萃取 在模板这里主要就是对于模板的不同类型的实例化 有不同的方案 这样可以提高效率等 

比如 下面的 顺序表 在扩容时的拷贝 

        对于没有含有指向空间的指针的类 如int 自动使用memcpy()

        对于含有指向空间的指针的类 如string 就自动一个一个的赋值 防止浅拷贝导致两个指针指向同一空间 析构两次时出错


类型萃取实现 主要用到了 模板  模板特化 内嵌型别  也可用函数重载 详见Copy()


//(1)-------类型萃取 实现顺序表

//----------------------Copy.h-------------------------


#ifndef __COPY_H__

#define __COPY_H__

#include<string>

#include<iostream>

using namespace std;


struct TrueType //内置类型

{

bool Get()

{

//cout<<"TrueType"<<endl;

return true;

}

};


struct FalseType //非内置类型

{

bool Get()

{

//cout<<"FalseType"<<endl;

return false;

}

};


template<class _Tp> //_Tp 类型 默认(没特化)使用 循环 一个一个赋值 

struct TypeTraits

{

typedef FalseType isPodType; //内嵌型别

};


//==========================

// 特化:实现同一个类型isPodType对于不同的特化表示的类型不同 如 FalseType/TrueType

// 使用 memcpy 的类型 用struct TypeTraits<...>{typedef TrueType isPodType; };

template<>

struct TypeTraits<int>

{

typedef TrueType isPodType; 

};


template<>

struct TypeTraits<char>

{

typedef TrueType isPodType; 

};


template<>

struct TypeTraits<float>

{

typedef TrueType isPodType; 

};


template<>

struct TypeTraits<double>

{

typedef TrueType isPodType; 

};

//还有未特化的 这里只是举几个例子 实际中应尽可能写完整......



// 使用 循环 一个一个赋值的类型 使用struct TypeTraits<...>{typedef FalseType isPodType; };

template<>

struct TypeTraits<string>

{

    typedef FalseType isPodType;

};

//==========================================

//============== 函数重载 的 应用 【Copy第一种方式的实现原理】==============


int m_copy(int a, int b, int)

{

return 0;

}


int m_copy(int a, int b, float)

{

return 0;

}

#if 0 //==========================

//============ 1 萃取  Copy的第1种方法 ==============

// 利用 函数重载来区分 FalseType  TrueType

template <typename T>

void Copy(T* dst, const T* src, int size, FalseType)

{

cout<<"__FalseType"<<typeid(T).name()<<endl;

for (int i = 0; i < size; ++i)

{

dst[i] = src[i];

}

}


template <typename T>

void Copy(T* dst, const T* src, int size, TrueType)

{

cout<<"__TrueType"<<typeid(T).name()<<endl;

memcpy(dst, src, size * sizeof(T));

}



void test2()

{

int arr1[] = {1,2,3,4,5,6,7,8,9};

int arr2[9];

int sz = sizeof(arr1)/sizeof(arr1[0]) ;

Copy<int>(arr2, arr1, sz, TypeTraits<int>::isPodType());


float arr3[] = {1.0, 2.1};// float 没有特化 走默认的TypeTraits

float arr4[2];

sz = sizeof(arr3)/sizeof(arr3[0]);

Copy<float>(arr4, arr3, sz, TypeTraits<float>::isPodType());

}

#endif //==========================

//============ 1 萃取  Copy的第2种方法 ==============

//               用模板函数

template<typename T>

void Copy(T* dst, const T* src, size_t size)

{

if(TypeTraits<T>::isPodType().Get())//使用类型isPodType构造匿名函数isPodType()

{

//cout<<"__TrueType"<<typeid(T).name()<<endl;

memcpy(dst, src, size * sizeof(T));

}

else 

{

//cout<<"FalseType"<<typeid(T).name()<<endl;

for (size_t i = 0; i < size; i++)

{

dst[i] = src[i];

}

}

}


#endif


//---------------   seq_list_by_cuiqu.cpp--------



#define _CRT_SECURE_NO_WARNINGS 1

#include "Copy.h"

template <typename T>

class SeqList

{

public:

SeqList();

SeqList(const SeqList& s);

~SeqList();


void PushBack(const T& d);

void PopBack();

void PushFront(const T& d);

void PopFront();

int Find(const T& d);

void Reverse();

void Insert(int pos, const T& d);

void sort();


SeqList& operator=(const SeqList& s);



void Print()

{

int i = 0;

for(i = 0; i < _size; i++)

{

cout<<_data[i]<<"  ";

}

cout<<endl;

}

private:

void _check_capacity()

{

if(_size == _capacity)

{

T* tmp = new T[2 * _capacity + 3];

//======注意 1 memcpy()浅拷贝问题 ===================

//对于含有指向动态开辟空间的类

//memcpy() 会出现浅拷贝现象 导致两个类的成员指针

//指向同一块空间 析构两次时导致【程序崩溃】

//比如 string类 内部含有这样一个指针

//当然 还有初始预留的空间 如果字符串没有超过预留空间

//指向动态空间的指针为空 用memcpy()也没事

//但当这个指针指向空间是 一等会由于浅拷贝导致析构

//失败的 

//==============================================

// memcpy(tmp, _data, _size * sizeof(T));


//===========================================

//解决方法

//利用 string类 自带的operator=()一个一个复制

//避免出现浅拷贝现象 

//不过memcpy()也有优点 那就是效率高

//===========================================



/*for(int i = 0; i < _size; i++)

{

tmp[i] = _data[i];

}*/


            // 更高效 使用【类型萃取】 对于可以使用memcpy的类型使用memcpy

            // 对于不可以使用memcpy的 使用 循环一个一个赋值 增强效率

            // 因为memcpy效率比较高

            Copy(tmp, _data, _size);

delete[] _data;

_data = tmp;

_capacity = 2 * _capacity + 3;

}

}



private:

int _size;

int _capacity;

T* _data;

};


//=================注意2 默认拷贝函数出现浅拷贝问题 ===========

//这要写 拷贝构造 防止出现浅拷贝问题

// 例如对于string这种含有指向动态开辟空间 的 指针成员

template <typename T>

SeqList<T>::SeqList(const SeqList<T>& s)

{

_data = new T[s._size];

int i = 0;

for(i = 0; i < s._size; i++)

{

_data[i] = _data[i];

}

_size = s._size;

_capacity = _size;

}


template <typename T>

SeqList<T>::SeqList()

:_size(0)

,_capacity(3)

,_data(new T[_capacity])//注意:声明类变量时要先声明_capacity 再声明_data 

{

//cout<<typeid(_capacity).name() <<endl;

//cout<<"SeqList()"<<endl;

}


template <typename T>

SeqList<T>::~SeqList()

{

if (_data != NULL)

{

delete[] _data;

_data = NULL;

}

}


template <typename T>

void SeqList<T>::PushBack(const T& d)

{

_check_capacity();

_data[_size] = d;

_size++;

}


template <typename T>

void SeqList<T>::PopBack()

{

if(_size > 0)

{

_size--;

}

}


template <typename T>

void SeqList<T>::PushFront(const T& d)

{

_check_capacity();

int i = _size;

while(i)

{

_data[i] = _data[i - 1];

i--;

}

_data[0] = d;

_size++;

}


template <typename T>

void SeqList<T>::PopFront()

{

int i = 0;

for(i = 0; i < _size - 1; i++)

{

_data[i] = _data[i + 1];

}

_size--;

}


template <typename T>

SeqList<T>& SeqList<T>::operator=(const SeqList& s)//注意用SeqList<T>&

{

if(this != &s)

{

delete[] _data;

_data = new T[s._capacity];

memcpy(_data, s._data, s._size * sizeof(T));

_size = s._size;

_capacity = s._capacity;

}

return *this;

}

template <typename T>

int SeqList<T>::Find(const T& d)

{

int i = 0;

for (i = 0; i < _size; i++)

{

if(_data[i] == d)

{

return i;

}

}

return -1;

}


template <typename T>

void SeqList<T>::Reverse()

{

int left = 0;

int right = _size - 1;

while(left < right)

{

swap(_data[left], _data[right]);

left++;

right--;

}

}


template <typename T>

void SeqList<T>::Insert(int pos, const T& d)

{

if(pos < 0 || pos > _size)

{

return;

}

_check_capacity();

int i = _size;

_size++;

while(i > pos)

{

_data[i] = _data[i - 1];

i--;

}

_data[pos] = d;

}


template <typename T>

void SeqList<T>::sort()

{

int i = 0;

for(i = 0; i < _size; i++)

{

bool flag = true;

for(int j = 0; j < _size - i - 1; j++)

{

if(_data[j] > _data[j + 1])

{

T temp = _data[j];

_data[j] = _data[j + 1];

_data[j + 1] = temp;

flag = false;

}

}

if(flag)

{

return;

}

}

}


int main()

{

{

//SeqList<int> s1;

/*s1.PushBack(1);

s1.PushBack(2);

s1.PushBack(3);

s1.PushBack(4);

s1.Print();


s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();

s1.PopBack();

s1.Print();*/


//s1.PushFront(1);

//s1.PushFront(2);

//s1.PushFront(3);

//s1.PushFront(4);

//s1.Print();


//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();

//s1.PopFront();

//s1.Print();


/*SeqList<string> s2;

s2.PushBack("1");

s2.PushBack("11111112222222222");

s2.Print();*/

//s2.PushBack();

//s2.PushBack();

//s2.PushBack();


SeqList <string> s1;

s1.PushBack("11111");

s1.PushBack("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");

s1.PushBack("33333");

s1.PushBack("44444");

s1.PushBack("44444");

/*s1.PushBack("44444");

s1.PushBack("44444");

s1.PushBack("44444");

s1.PushBack("44444");

s1.PushBack("44444");

s1.PushBack("44444");*/


s1.Print();


    SeqList <int> s3;

s3.PushBack(1);

s3.PushBack(2);

s3.PushBack(3);

s3.PushBack(4);

s3.PushBack(5);

    s3.Print();

//SeqList <string> s2(s1);

//s2 = s1;

//s2.Print();


/*s1.PushBack(4);

s1.PushBack(3);

s1.PushBack(2);

s1.PushBack(1);

s1.Print();*/


/*s1.sort();

s1.Print();

cout<<s1.Find(3)<<endl;

s1.Insert(s1.Find(3),4);

s1.Print();*/


/*SeqList<int> s2 = s1;

s2.Print();*/


}

//test2();

getchar();

return 0;

}


//====================================================

//(2) 容器适配器

    容器适配器 允许 模板参数 是模板类的类类型

// Container 适配器练习

//template <typename T, typename Container>


//模板的模板参数

template <typename T, template<class> class Container = SeqList>

class Stack

{

public:

void Push(const T& d)

{

con.PushBack(d);

}

void Pop()

{

con.PopBack();

}

private:

Container<T> con;

};


int main()

{

//SeqList<int> seq;

Stack<int, SeqList> stack1;

Stack<int> stack2;

stack1.Push(1);

stack1.Pop();

return 0;

}


#endif



//#include <vector>

//int main()

//{

// int b;

// vector<int> vec;

// vec.push_back(1);

// vec.push_back(2);

// return 0;

//}


//#include <list>

//int main()

//{

// list<string> vec;

// vec.push_back("aaaaaa");

// vec.push_back("bbbbbbbb");

// return 0;

//}


//小知识点

//========隐式转换


class D

{

public:

    explicit D(int d)

        :_d(d)

    {cout<<"D()"<<endl;}

private:

    int _d;

};



int main()

{

    D d = 1; //防止使用D(int d)构造函数 隐式转换 可以使用关键字explicit 阻止隐式转换

    getchar();

return 0;

}


本文出自 “城市猎人” 博客,请务必保留此出处http://alick.blog.51cto.com/10786574/1758122

以上是关于C++ 模板 之 类型萃取 与 容器适配器的主要内容,如果未能解决你的问题,请参考以下文章

C++顺序容器

C++ STL教程(13)容器适配器使用

C++ STL容器适配器 内容详解

C++——stack和queue的模拟实现

关联容器

STL之stack等容器适配器