C++11中的模板特例化

目錄

函數模板特例化

類模板特例化


  最近在看智能指針的源碼,發現其中用了很多模板特例化,本文就來總結一下,什麼是模板特例化。

      特例化,顧名思義:特殊實例化,將函數模板或類模板實例化爲特殊的類型,通過模板特例化可以定製在特定模板參數下的函數模板/類模板實現,或者禁用特定模板的函數模板/類模板

函數模板特例化

       既然是特例化,那麼自然就需要有一個“原型”,現在假設一個原型模板函數compare,用來比較傳入的兩個參數的大小,如下所示:

template<typename T>
bool compare(T param1,T param2)
{
	return param1 < param2;
}

      通過這個模板函數,可以傳入任意類型的兩個參數,如compare(1,2); compare(1.1,2.1);

      那要是compare("hello","hey");呢?傳入的兩個參數類型爲const char *類型的指針,這種情況如果還只是比較兩個指針的大小,顯然是不行的,應當使用strcmp來比較。所以,當模板參數類型爲const char *類型時,這就需要進行“特例化”了,特例化compare如下所示:

template<>
bool compare(const char * str, const char * str2)
{
	cout << (str < str2) << endl;
	return strcmp(str, str2) < 0;
}

      由於前面只有一個模板參數T,特例化T後就沒有模板參數了,所以在特例化模板函數中template 參數爲空。這就相當於把原模板進行T = const char *的實例化,當T爲const char *的時候就直接調用特例化的compare。需要注意的是,這裏的特例化模板函數並不是模板重載,它一樣是匹配原模板,只不過在T爲const char *時使用特例compare。

 

       上面是模板參數全部特例化的例子,也可以進行部分特例化,如下所示:

template<typename T1, typename T2>
void fun(T1 param1, T2 param2)    //原模板
{
	cout << "orginal template" << endl;
}

template<typename T>
void fun(T param1, int param2)    //第二個參數爲Int時的特例化模板
{
	cout << "special template" << endl;
}

int main
{
    fun(1,1.0);    //使用原模板函數
    fun(1,1);      //使用特例化模板函數
    return 0;
}

        特例化的一個好處就是可以在不能/不希望使用某些模板參數下的模板時,對其進行禁用。比如說上面的fun函數,我不希望第二個參數爲int,那麼就可以禁用這種特例化模板,這樣當傳入的第二個實參爲int型時,編譯器就會報錯。

template<typename T1, typename T2>
void fun(T1 param1, T2 param2)    //原模板
{
	cout << "orginal template" << endl;
}

template<typename T>
void fun(T param1, int param2) = delete ;    //禁用第二個參數爲Int時的特例化模板

/*   也可以只聲明不定義
template<typename T>
void fun(T param1, int param2);
*/

int main
{
    fun(1,1.0);    //使用原模板函數
    fun(1,1);      //報錯,編譯器不通過
    return 0;
}

        在禁用特例化的情況下,fun(1,1)也沒有去調用原模板函數,這也說明了特例化並非重載(如果是重載的話,那麼就會直接調用第一個模板函數)。 

類模板特例化

      現在假定一個模板類A,接收兩個模板參數,第二個模板參數爲bool類型,現在將第二個模板參數爲true進行特例化,如下所示:

template<class T,bool b>  //原模板
class My 
{
public:
	void fun()
	{
		cout << "original" << endl;
	}
};

template<class T>     //特例化第二個參數爲true時相應的模板
class My < T, true >
{
public:
	void fun()
	{
		cout << "special" << endl;
	}
};

My<double,false> m;
m.fun();     //使用原模板  打印“original”

My<int,true>n;
n.fun();     //使用特例化模板  打印“speacial”

         上面這個例子其實就是unique_ptr源碼中的一部分,參考_Unique_ptr_base模板特例化 。

         這只是特例化了一個模板參數,當然也可以把所有參數都特例化,在上面程序的基礎上再加上如下代碼:

template<>     //特例化兩個模板參數
class My < int, true >
{
public:
	void fun()
	{
		cout << "special special" << endl;
	}
};

       這就相當於把原模板中的兩個參數都進行了特例化,需要注意的是,此時如果再使用n.fun(),那麼打印的結果則是“special  special”,可以看到,模板實例會優先匹配特例化程度更高的模板。

 

       和禁用某種模板下的函數模板相同,也可以禁用某種模板下的類模板。比如說我希望禁用第二個模板參數爲true的模板,那麼就可以對其進行不完整定義,如下所示:

template<class T>     //特例化第二個參數爲true時相應的模板
class My < T, true >;  //不完整定義

My<int,true>n;  //編譯出錯
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章