1. 程式人生 > >c++模板、模板的全特化與偏特化

c++模板、模板的全特化與偏特化

1. c++模板的一般使用方法

 1. 類模板

#include<iostream>
using namespace std;
template <typename T>
class MyClass
{
public:
	MyClass <T>(T a, T b)
	{
		this->a = a;
		this->b = b;
	}
public:
	T GetA()
	{
		return this->a;
	}
	T GetB()
	{
		return this->b;
	}
private:
	T a;
	T b;
};
int main()
{
	//MyClass mc; //錯誤,必須指定型別,因為要開闢空間
	MyClass<int> mc(3, 4);
	cout << "mc.a:" << mc.GetA() << '\n' << "mc.b:" << mc.GetB() << endl;
    return 0;
}

輸出結果:

我們再嘗試將成員函式在類外定義:

template <typename T>
class MyClass
{
public:
	MyClass <T>(T a, T b)
	{
		this->a = a;
		this->b = b;
	}
public:
	T GetA();
	T GetB();
private:
	T a;
	T b;
};
T MyClass::GetA()
{
	return this->a;
}
T MyClass::GetB()
{
	return this->b;
}

 如果以這種常規形式類外定義類成員,我們發現是無法通過編譯的:

第一個問題:T編譯器不認識了;

第二個問題:缺少類模板MyClass的引數列表

為了讓編譯器再次認識T,我們將template <typename T>拿到每個函式上面;然後在MyClass後面加上模板引數列表:

template <typename T>
T MyClass<T>::GetA()
{
	return this->a;
}
template <typename T>
T MyClass<T>::GetB()
{
	return this->b;
}

這樣程式就可以正常的運行了。

小結論:在類外定義模板類成員函式時,格式為:template<T> 返回值   類名<T>:: 函式名(){} ;

另外,在所有出現MyClass的地方都需要模板引數列表。

2. 函式模板

#include<iostream>
using namespace std;
template <typename T>
T Add(T a, T b)
{
	return a + b;
}
int main()
{
	cout << Add(1, 2) << endl;
    return 0;
}

可以看到:呼叫Add時並沒有在Add後新增模板引數列表。

執行結果:

小結論:類模板不能自動推演模板的型別,而函式模板可以根據引數自動匹配。

 2. c++類模板的全特化

#include<iostream>
using namespace std;
template <typename T1, typename T2>
class MyClass
{
public:
	MyClass <T1, T2>(T1 a, T2 b)
	{
		this->a = a;
		this->b = b;
	}
public:
	T1 GetA(){return this->a;}
	T2 GetB(){return this->b;}
private:
	T1 a;
	T2 b;
};
//實現了MyClass的全特化
template <>
class MyClass<int, char>
{
public:
	MyClass (int a, char b)
	{
		this->a = a;
		this->b = b;
	}
public:
	int GetA(){return this->a;}
	char GetB(){return this->b;}
private:
	int a;
	char b;
};
int main()
{
	//MyClass mc; //錯誤,必須指定型別,因為要開闢空間
	MyClass<int, char> mc(3, 'c');
	cout << "mc.a:" << mc.GetA() << '\n' << "mc.b:" << mc.GetB() << endl;
    return 0;
}

執行結果:

顯而易見,全特化的意思就是將原本模板的泛型引數全部變成了指定的型別。

 3. c++類模板的偏特化

 理解了全特化,偏特化就不難理解了:

template <typename T1, typename T2>
class MyClass
{
public:
	MyClass <T1, T2>(T1 a, T2 b)
	{
		this->a = a;
		this->b = b;
	}
public:
	T1 GetA(){return this->a;}
	T2 GetB(){return this->b;}
private:
	T1 a;
	T2 b;
};
template <typename T2>
class MyClass<int, T2>
{
public:
	MyClass (int a, T2 b)
	{
		this->a = a;
		this->b = b;
	}
public:
	int GetA(){return this->a;}
	T2 GetB(){return this->b;}
private:
	int a;
	T2 b;
};

可以看出,偏特化就是原本模板的泛型引數部分變成了指定的型別。

4. 三種類模板型別的呼叫優先順序

#include<iostream>
using namespace std;
template <typename T1, typename T2>
class MyClass
{
public:
	MyClass(){}
public:
	void WhoAmI()
	{
		cout << "I am general one" << endl;
	}
};
template <>
class MyClass<int, char>
{
public:
	MyClass(){}
public:
	void WhoAmI()
	{
		cout << "I am complete one" << endl;
	}
};
template <typename T2>
class MyClass<int, T2>
{
public:
	MyClass(){}
public:
	void WhoAmI()
	{
		cout << "I am incomplete one" << endl;
	}
};
int main()
{
	MyClass<int, char> mc1;
	mc1.WhoAmI();
	MyClass<int, double> mc2;
	mc2.WhoAmI();
	MyClass<char, double> mc3;
	mc3.WhoAmI();
    return 0;
}

執行結果:

小結論:對於三種類模板的呼叫優先順序從高到低為:全特化>偏特化>一般。