C++模板全特化(具體化)與偏特化(部分具體化)詳解

1.模板簡介

模板就是實現代碼重用的一種機制,它可以實現類型參數化,即把類型定義爲參數, 從而實現了真正的代碼可重用性。

模板編程和函數重載可以實現C++靜態多態,也叫編譯時多態

模版可以分爲兩類,一個是 函數模版 ,另一個是 類模版

2.模板特化的目的

模板本來是一組通用邏輯的實現,但是可能存在特定的參數類型下,通用的邏輯實現不能滿足要求,這時就需要針對這些特殊的類型,而實現一個特例模板—即模板特化。

3.重點注意

1)類模板和函數模板都可以被全特化;

2)類模板能偏特化,不能被重載;

3)函數模板可以實現重載,不能被偏特化;

4)類模板調用優先級:全特化類>偏特化類>主版本模板類;

5)注意模板編程不支持分離式編譯,即模板類/模板函數的聲明與定義應該放在頭文件裏,否則會在鏈接時報錯;

6)函數模板同時存在具體化模板、函數模板重載、和常規函數重載時候,調用優先級:

常規函數 > 具體化模板函數 > 常規模板函數;

注意:重載決議時,優先決議出是不是符合常規函數,不存在符合的普通函數,纔會再決議出符合的函數主模板,對於函數模板重載決議,會無視特化存在(標準規定:重載決議無視模板特化,重載決議發生在主模板之間),決議出函數主模板後,如果函數主模板存在符合的具體化函數模板,纔會調用具體化函數模板;

7)不能將函數模板特化和重載混爲一談
函數特化都沒有引入一個全新的模板或者模板實例,它們只是對原來的主(或者非特化)模板中已經隱式聲明的實例提供另一種定義。在概念上,這是一個相對比較重要的現象,也是特化區別於重載模板的關鍵之處。

如果使用普通重載函數,那麼不管是否發生實際的函數調用,都會在目標文件中生成該函數的二進制代碼。而如果使用函數模板特化版本,除非發生函數調用,否則不會在目標文件中包含特化模板函數的二進制代碼。這符合函數模板的“惰性實例化”準則。

4.函數模板

1)常規函數

// 常規函數
void Compare(const char* first, const char* second)
{
	cout << "const char* ordinary function " << endl;
	if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
	{
		cout << "first:" << first << " > second:" << second << endl;
	}
	else
	{
		cout << "first:" << first << " <= second:" << second << endl;
	}
}

2)函數主模板a

//函數主模板
template<typename T, typename N> void Compare(T first, N second)
{
	cout << "Standard function template <T, N>" << endl;
	if (first < second)
	{
		cout << "first < second" << endl;
	}
	else
	{
		cout << "first >= second" << endl;
	}
}

3)函數模本b--全特化

針對char*類型的比較函數,不能直接使用大於號或小於號比較元素,需要特化;

//函數模板-全特化
template<> void Compare(const char* first, const char* second)
{
	cout << "const char* specialization <const char*, const char*>" << endl;
	if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
	{
		cout << "first:" << first << " > second:" << second << endl;
	}
	else
	{
		cout << "first:" << first << " <= second:" << second << endl;
	}
}

4)函數模板c-重載,作爲一個獨立的函數主模板

//函數模板-重載,不是偏特化,它會作爲一個獨立的函數主模板
template<typename T, typename N> void Compare(T* first, N* second)
{
	cout << "function template overload <T*, N*>" << endl;
	cout << "T type: " << typeid(T).name() << ", N type : " << typeid(N).name() << endl;
	if (strcmp(typeid(T).name(), "char") == 0 && strcmp(typeid(N).name(), "char") == 0)
	{
		if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
		{
			cout << "first:" << first << " > second:" << second << endl;
		}
		else
		{
			cout << "first:" << first << " <= second:" << second << endl;
		}
	}
	else
	{
		if (*first < *second)
		{
			cout << "first < second" << endl;
		}
		else
		{
			cout << "first >= second" << endl;
		}
	}
}

5)函數模板之間的重載決議

【1】當代碼中存在如下順序的申明時,

template<typename T, typename N> void Compare(T first, N second) //函數主模板a

{.....}

template<> void Compare(const char* first, const char* second) // 函數主模板a的全特化模板 b

{.....}

template<typename T, typename N> void Compare(T* first, N* second) // 函數主模板c,是函數主模板a的重載

{.....}

那麼,發生如下函數調用時,

Compare("1", "2");

會打印輸出:

這裏顯示實際調用了函數主模板c,

因爲在調用Compare("1", "2")時,先會進行重載決議

發生重載決議,會無視特化存在(標準規定:重載決議無視模板特化,重載決議發生在主模板之間),

那麼就會決議出函數主模板c;

【2】當代碼中存在如下順序的申明時,

template<typename T, typename N> void Compare(T first, N second) //函數主模板a

{.....}

template<typename T, typename N> void Compare(T* first, N* second) // 函數主模板b,是函數主模板a的重載

{.....}

template<> void Compare(const char* first, const char* second) // 此時是函數主模板b的全特化模板 ,爲全特化函數模板c

{.....}

那麼,發生如下函數調用時,

Compare("1", "2");

會打印輸出:

這裏顯示實際調用了全特化函數模板c,

因爲在調用Compare("1", "2")時,先會進行重載決議

發生重載決議,會無視特化存在(標準規定:重載決議無視模板特化,重載決議發生在主模板之間),

那麼就會決議出函數主模板b,在判斷函數主模板存在符合類型條件的全特化模板c

函數模板特化與重載決議

6)常規函數與函數模板之間的重載決議

當代碼中存在如下順序的申明時,

template<typename T, typename N> void Compare(T first, N second) //函數主模板a

{.....}

template<> void Compare(const char* first, const char* second) // 函數主模板a的全特化模板 b

{.....}

template<typename T, typename N> void Compare(T* first, N* second) // 函數主模板c,是函數主模板a的重載

{.....}
void Compare(const char* first, const char* second) // 常規函數

{.....}

那麼,發生如下函數調用時,

Compare("1", "2");

會打印輸出:

這裏顯示實際調用了常規函數,

因爲在調用Compare("1", "2")時,先會進行重載決議,重載決議會優先決議是否存在符合條件的常規函數。

7)函數模板全部實現

/******************************* template function start ****************************************/

//函數主模板
template<typename T, typename N> void Compare(T first, N second)
{
	cout << "Standard function template <T, N>" << endl;
	if (first < second)
	{
		cout << "first < second" << endl;
	}
	else
	{
		cout << "first >= second" << endl;
	}
	cout << endl;
}

//函數模板-全特化
template<> void Compare(const char* first, const char* second)
{
	cout << "const char* specialization <const char*, const char*>" << endl;
	if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
	{
		cout << "first:" << first << " > second:" << second << endl;
	}
	else
	{
		cout << "first:" << first << " <= second:" << second << endl;
	}
	cout << endl;
}

//函數主模板-重載,不是偏特化,它會作爲一個獨立的函數主模板
template<typename N> void Compare(int first, N second)
{
	cout << "partitial specialization <int, N>" << endl;
	if (first < second)
	{
		cout << "first < second" << endl;
	}
	else
	{
		cout << "first >= second" << endl;
	}
	cout << endl;
}

//函數模板-重載,不是偏特化,它會作爲一個獨立的函數主模板
template<typename T, typename N> void Compare(T* first, N* second)
{
	cout << "function template overload <T*, N*>" << endl;
	cout << "T type: " << typeid(T).name() << ", N type : " << typeid(N).name() << endl;
	if (strcmp(typeid(T).name(), "char") == 0 && strcmp(typeid(N).name(), "char") == 0)
	{
		if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
		{
			cout << "first:" << first << " > second:" << second << endl;
		}
		else
		{
			cout << "first:" << first << " <= second:" << second << endl;
		}
	}
	else
	{
		if (*first < *second)
		{
			cout << "first < second" << endl;
		}
		else
		{
			cout << "first >= second" << endl;
		}
	}
	cout << endl;
}

//函數主模板-重載,不是偏特化,它會作爲一個獨立的函數主模板
template<typename T, typename N> void Compare(std::vector<T>& first, std::vector<N>& second)
{
	cout << "to vector partitial specialization <std::vector,std::vector>" << endl;
	if (first.size() < second.size())
	{
		cout << "first.size() < second.size()" << endl;
	}
	else
	{
		cout << "first.size() >= second.size()" << endl;
	}
	cout << endl;
}

// 常規函數
void Compare(const char* first, const char* second)
{
	cout << "const char* ordinary function " << endl;
	if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
	{
		cout << "first:" << first << " > second:" << second << endl;
	}
	else
	{
		cout << "first:" << first << " <= second:" << second << endl;
	}
	cout << endl;
}

// 測試函數模板功能
void Test_Temmplate_Function()
{
	cout << __FUNCTION__ << ":" << endl;
	Compare(1,2);
	Compare(1, 2.0);
	Compare(1.0, 2.0);
	Compare('1', '2');
	Compare("1", "2");
	vector<int> v1 = { 1 };
	vector<int> v2 = { 2 };
	Compare(v1, v2);
	cout << endl;
}

/******************************* template function end ****************************************/

打印輸出如下圖,

5.類模板

必須先有泛化版本類模板(主模板),纔有特化版本類模板。

1)類模板特化分類

特化爲絕對類型(全特化);

特化爲引用,指針類型(半特化、偏特化);

特化爲另外一個類模板(複雜點的偏特化)

2)類模板-主模板類

//類模板-主版本模板類
template<typename T, typename N> class MyClass
{
public:
	 void Compare(T first, N second)
	{
		cout << "standard function template" << endl;
		cout << __FUNCTION__ << ":" << endl;
		if (first < second)
		{
			cout << "first < second" << endl;
		}
		else
		{
			cout << "first >= second" << endl;
		}
	}
};

3)類模板-全特化(具體化)

//類模板-全特化(具體化)
template<> class MyClass<const char*, const char*>
{
public:
	 void Compare(const char* first, const char* second)
	{
		cout << "const char* specialization" << endl;
		cout << __FUNCTION__ << ":" << endl;
		if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
		{
			cout << "first:" << first << " > second:" << second << endl;
		}
		else
		{
			cout << "first:" << first << " <= second:" << second << endl;
		}
	}
};

4)類模板-特化(部分具體化),對部分模板參數進行特化爲一般類型

//類模板-特化(部分具體化),對部分模板參數進行特化
template<typename N> class MyClass<int, N>
{
public:
	void Compare(int first, N second)
	{
		cout << "partitial specialization" << endl;
		cout << __FUNCTION__ << ":" << endl;
		if (first < second)
		{
			cout << "first < second" << endl;
		}
		else
		{
			cout << "first >= second" << endl;
		}
	}
};

5)類模板-特化(部分具體化),將模板參數特化爲指針

//類模板-特化(部分具體化),將模板參數特化爲指針
template<typename T, typename N> class MyClass<T*, N*>
{
public:
	 void Compare(T* first, N* second)
	{
		cout << "ptr partitial specialization" << endl;
		cout << __FUNCTION__ << ":" << endl;
		if (first < second)
		{
			cout << "first < second" << endl;
		}
		else
		{
			cout << "first >= second" << endl;
		}
	}
};

6)類模板-特化(部分具體化),將模板參數特化爲另一個模板類

//類模板-特化(部分具體化),將模板參數特化爲另一個模板類
template<typename T, typename N> class MyClass<vector<T>, vector<N>>
{
public:
	void Compare(const vector<T>& first, const vector<N>& second)
	{
		cout << "to vector partitial specialization" << endl;
		cout << __FUNCTION__ << ":" << endl;
		if (first.size() < second.size())
		{
			cout << "first.size < second.size" << endl;
		}
		else
		{
			cout << "first.size >= second.size" << endl;
		}
	}
};

7)類模板特化全部實現


/******************************* template class start ****************************************/

//類模板-主版本模板類
template<typename T, typename N> class MyClass
{
public:
	 void Compare(T first, N second)
	{
		cout << "standard function template" << endl;
		cout << __FUNCTION__ << ":" << endl;
		if (first < second)
		{
			cout << "first < second" << endl;
		}
		else
		{
			cout << "first >= second" << endl;
		}
	}
};

//類模板-全特化(具體化)
template<> class MyClass<const char*, const char*>
{
public:
	 void Compare(const char* first, const char* second)
	{
		cout << "const char* specialization" << endl;
		cout << __FUNCTION__ << ":" << endl;
		if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
		{
			cout << "first:" << first << " > second:" << second << endl;
		}
		else
		{
			cout << "first:" << first << " <= second:" << second << endl;
		}
	}
};

//類模板-特化(部分具體化),對部分模板參數進行特化
template<typename N> class MyClass<int, N>
{
public:
	void Compare(int first, N second)
	{
		cout << "partitial specialization" << endl;
		cout << __FUNCTION__ << ":" << endl;
		if (first < second)
		{
			cout << "first < second" << endl;
		}
		else
		{
			cout << "first >= second" << endl;
		}
	}
};

//類模板-特化(部分具體化),將模板參數特化爲指針
template<typename T, typename N> class MyClass<T*, N*>
{
public:
	 void Compare(T* first, N* second)
	{
		cout << "ptr partitial specialization" << endl;
		cout << __FUNCTION__ << ":" << endl;
		if (first < second)
		{
			cout << "first < second" << endl;
		}
		else
		{
			cout << "first >= second" << endl;
		}
	}
};

//類模板-特化(部分具體化),將模板參數特化爲另一個模板類
template<typename T, typename N> class MyClass<vector<T>, vector<N>>
{
public:
	void Compare(const vector<T>& first, const vector<N>& second)
	{
		cout << "to vector partitial specialization" << endl;
		cout << __FUNCTION__ << ":" << endl;
		if (first.size() < second.size())
		{
			cout << "first.size < second.size" << endl;
		}
		else
		{
			cout << "first.size >= second.size" << endl;
		}
	}
};

// 測試類模板功能
void Test_Temmplate_Class()
{
	cout << __FUNCTION__ << ":" << endl;

	MyClass<char, int> c_i_myclass;
	c_i_myclass.Compare(1, 2);
	printf("function address: %p\n\n", &MyClass<char,int>::Compare);

	MyClass<int, double> i_d_myclass;
	i_d_myclass.Compare(1, 2);
	printf("function address: %p\n\n", &MyClass<int, double>::Compare);

	MyClass<int, int> i_i_myclass1;
	i_i_myclass1.Compare(1, 2);
	printf("function address: %p\n\n", &MyClass<int, int>::Compare);

	MyClass<int, int> i_i_myclass2;
	i_i_myclass2.Compare(1, 2);
	printf("function address: %p\n\n", &MyClass<int, int>::Compare);

	MyClass<const char*, const char*> c_c_c_c_myclass;
	c_c_c_c_myclass.Compare("1", "2");
	printf("function address: %p\n\n", &MyClass<const char*, const char*>::Compare);

	MyClass<vector<int>, vector<char>> vc_i_vc_c_maclass;
	vc_i_vc_c_maclass.Compare({ 1 }, { 1,2 });
	printf("function address: %p\n\n", &MyClass<vector<int>, vector<char>>::Compare);

	cout << endl;
}

/******************************* template class end ****************************************/

執行後打印輸出如下圖所示,

可以看到MyClass<int, int>類型聲明的對象,函數Compare地址是一樣的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章