C++ — 模板

函數模板

函數模板的定義

template<class T>	//模板參數列表    不能使用struct    //自動識別參數類型
template<typename T>        //自動識別參數類型
//typename是用來定義模板參數的關鍵字,也可以使用class
//template<int T>     //編譯出錯
T Add(T left, T right)	//函數模板
{
	return left + right;
}
Add(1, 2); 	//模板的實例化

template<class T1, class T2>    //多個類型參數
T2 Add(T1 left, T2 right)
{
	return left + right;
}
Add(1, 2.0); 

函數模板的原理

模板是一個藍圖,本身並不是函數,是編譯器用使用方式產生特定具體類型函數的模具,在調用時編譯器會根據調用方式生成函數代碼
模板匹配規則

  1. 一個非模板函數可以和同名的一個函數模板存在,而且該函數模板還可以被實例化爲這個非模板函數
  2. 對於非模板函數和同名函數模板,如果其他條件都相同,在調用時會優先調用非模板函數而不會從該模板產生一個實例,如果模板可以產生一個具有更好的匹配函數,那麼將選擇模板
  3. 模板函數不允許自動類型轉化,但普通函數可以自動類型轉化
T Add(T left, T right)
{
	return left + right;
}
int Add(int left, int right)    //參數類型符合時,會調用用戶自己實現的,且編譯器不會再生成
{
    return left + right;
}

函數模板的實例化

多次調用,只生成一份代碼

//隱式實例化
Add(1,2);	//對實參進行類型推演,生成處理具體類型的函數
//不會進行隱式類型轉化(除數組——>指針、函數名——>函數指針)
 
//顯示實例化
Add<int>(1,2);    //確定的參數類型,會進行隱式類型轉化 
//顯示實例化時,編譯器必須生成代碼

Add<>(1,2);    //隱式實例化,但也需要生成代碼

類模板

類模板的定義

template<class T1, class T2, ..., class Tn>
class 類模板名
{
// 類內成員定義
};

類模板的實例化

類模板實例化與函數模板實例化不同,類 模板實例化需要在類模板名字後跟<>,然後將實例化的類型放在<>中即可,類模板名字不是真正的類,而實例化的結果纔是真正的類。 在這裏,我們實現一個簡單的棧,來展示一個類模板。

#define MAXSIZE 10
template<class T>
class STACK
{
public:
	STACK()
	{
		_pStack = new T[10];
		_size = 0;
	}
	void StackPush(T data)
	{
		if (_size == MAXSIZE)
		{
			std::cout << "full" << std::endl;
			return;
		}
		_pStack[_size] = data;
		++_size;
	}
	void StackPop()
	{
		if (_size == 0)
		{
			std::cout << "empty" << std::endl;
			return;
		}
		--_size;;
	}
	T StackTop()
	{
		if (_size == 0)
		{
			std::cout << "empty" << std::endl;
			return -1;
		}
		return _pStack[_size - 1];
	}
	~STACK()
	{
		delete[] _pStack;
		_pStack = nullptr;
		_size = 0;
	}
private:
	T* _pStack;
	int _size;
};


STACK<int> s;

非類型模板

模板參數

類型形參:出現在模板參數列表中,跟在class或者typename之類的參數
非類型形參:用一個常量作爲類(函數)模板的一個參數

//非類型模板參數 N    常量
template<class T, size_t N>

//函數
//數組引用,類似於數組指針
void print(const T (&array)[N])    
{ 
)
print(arr);    //編譯器會把元素個數傳遞給N
//類
template<class T, size_t N>
class Array
{
    T _array[N];
}
Array<int, 100> arr;

注意

  1. 浮點數、類對象以及字符串是不允許作爲非類型模板參數的
  2. 非類型模板參數必須在編譯期就能確認結果

模板的特化

在原模板類的基礎上,針對特殊類型所進行特殊化的實現方式

函數模板的特化

必須要先有一個基礎的函數模板,那種類型不能處理,特殊化處理該種類型

  1. 關鍵字template後面接一對空的尖括號<>
  2. 函數名後跟一對尖括號,尖括號中指定需要特化的類型
  3. 用需要特化的類型替換掉所有的T
/*
假設char*需要特殊處理,用char*替換掉所有的T
需要特化類型,將什麼類型跟在函數名之後
*/
Template<> 
bool IsEqual<char*>(char*& left, char*& right) 
{    
    if(strcmp(left, right) > 0)        
        return true;        
    return false; 
}
//一般情況下如果函數模板遇到不能處理或者處理有誤的類型,爲了實現簡單通常都是將該函數直接給出(簡單)。
bool IsEqual(char* left, char* right) 
{    
    if(strcmp(left, right) > 0)        
        return true;        
    return false; 
}
//在模板中,const T pa,const實際是修飾的是pa

類模板的特化

全特化

全特化即是將模板參數類表中所有的參數都確定化

template<class T1, class 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; 
};

偏特化

任何針對模版參數進一步進行條件限制設計的特化版

部分特化

將模板參數類表中的一部分參數特化

//將第二個參數特化
int template <class T1> 
class Data<T1, int> 
{ 
public:    
    Data()
    {
    cout<<"Data<T1, int>" <<endl;
    } 
private:    
    T1 _d1;    
    int _d2; 
};
特化類型
//兩個參數偏特化爲指針類型 
template <typename T1, typename T2> 
class Data <T1*, T2*>
{ 
public:    
    Data() 
    {
    cout<<"Data<T1*, T2*>" <<endl;
    }    
private:    
    T1 _d1;    
    T2 _d2; 
};
//兩個參數偏特化爲引用類型 
template <typename T1, typename T2> 
class Data <T1&, T2&> 
{ 
public:    
    Data(const T1& d1, const T2& d2)        
        : _d1(d1)        , _d2(d2)    
    {            
    cout<<"Data<T1&, T2&>" <<endl;    
    }    
private:    
    const T1 & _d1;    
    const T2 & _d2;     
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章