【c++ templates讀書筆記】【4】技巧性基礎知識

1、關鍵字typename

引入關鍵字typename是爲了說明:模板內部的標識符可以是一個類型。當某個依賴與模板參數的名稱是一個類型時,就應該使用typename。

template<T>
class MyClass{
	typename T::SubType * ptr;  // typename說明SubType是定義於T內的一種類型,如果不使用typename,SubType會被認爲是T的一個靜態成員
	...
};

2、使用this->

對於那些在基類中聲明,並且依賴於模板參數的符號(函數或變量等),應該在它們前面使用this->或者Base<T>::。

#include<iostream>
using namespace std;

template<typename T>
class Base{
public:
	void exit(){ cout << "exit" << endl; }
};
template<typename T>
class Derived:Base<T>{
public:
	void exitDerived(){
		this->exit();//但VS 2013中直接用exit()也能正確運行
	}
};
int main(){
	Derived<int> d;
	d.exitDerived();

	system("pause");
	return 0;
}

3、成員模板

嵌套類和成員函數都可以作爲模板,例子:
#include<iostream>
#include<deque>
using namespace std;

template<typename T>
class Stack{
private:
	deque<T> deq;
public:
	void push(T const& elem);
	void pop();
	T top() const;
	bool empty() const{
		return deq.empty();
	}
	template<typename T2>//成員模板
	Stack<T>& operator=(Stack<T2> const& op2);
};
template<typename T>
void Stack<T>::push(T const& elem){
	deq.push_back(elem);
}
template<typename T>
void Stack<T>::pop(){
	if (deq.empty()){
		throw out_of_range("Stack<>::pop():empty stack");
	}
	deq.pop_back();
}
template<typename T>
T Stack<T>::top() const{
	if (deq.empty()){
		throw out_of_range("Stack<>::pop():empty stack");
	}
	return deq.back();
}
template<typename T>
template<typename T2>
Stack<T>& Stack<T>::operator=(Stack<T2> const& op2){
	if ((void*)this == (void*)&op2)
		return *this;
	Stack<T2> tmp(op2);
	deq.clear();
	while (!tmp.empty()){
		deq.push_front(tmp.top());
		tmp.pop();
	}
	return *this;
}

int main(){
	try{
		Stack<float> istk;
		istk.push(7.2);
		istk.push(8.3);
		istk.push(9.4);
		cout << istk.top() << endl;
		istk.pop();
		cout << istk.top() << endl;

		Stack<int> sstk;
		sstk = istk;
		cout << sstk.top() << endl;
		sstk.pop();
		cout << sstk.top() << endl;
	}
	catch (exception const& ex){
		cerr << "Exception:" << ex.what() << endl;
		return EXIT_FAILURE;
	}

	system("pause");
	return 0;
}

4、模板的模板參數

模板參數本身是模板,則該參數是模板的模板參數。函數模板不支持模板的模板參數。

例子:

#include<iostream>
#include<deque>
#include<vector>
using namespace std;
//這裏Container是模板的模板參數
template<typename T,template<typename ELEM,typename=allocator<ELEM>> class Container=deque>
class Stack{
private:
	Container<T> container;
public:
	void push(T const& elem);
	void pop();
	T top() const;
	bool empty() const{
		return container.empty();
	}
	template<typename T2, template<typename ELEM2, typename = allocator<ELEM2>> class Container2>
		Stack<T, Container>& operator=(Stack<T2, Container2> const& op2);
};
template<typename T, template<typename ELEM, typename = allocator<ELEM>> class Container>
void Stack<T,Container>::push(T const& elem){
	container.push_back(elem);
}
template<typename T, template<typename ELEM, typename = allocator<ELEM>> class Container>
void Stack<T, Container>::pop(){
	if (container.empty()){
		throw out_of_range("Stack<>::pop():empty stack");
	}
	container.pop_back();
}
template<typename T, template<typename ELEM, typename = allocator<ELEM>> class Container>
T Stack<T, Container>::top() const{
	if (container.empty()){
		throw out_of_range("Stack<>::pop():empty stack");
	}
	return container.back();
}
template<typename T, template<typename ELEM, typename = allocator<ELEM>> class Container>
template<typename T2, template<typename ELEM2, typename = allocator<ELEM2>> class Container2>
Stack<T, Container>& Stack<T, Container>::operator=(Stack<T2, Container2> const& op2){
	if ((void*)this == (void*)&op2)
		return *this;
	Stack<T2, Container2> tmp(op2);
	container.clear();
	while (!tmp.empty()){
		container.push_front(tmp.top());
		tmp.pop();
	}
	return *this;
}

int main(){
	try{
		Stack<double> dstk;
		dstk.push(7.2);
		dstk.push(8.3);
		dstk.push(9.4);
		cout << dstk.top() << endl;
		dstk.pop();
		cout << dstk.top() << endl;

		Stack<int> istk;
		istk = dstk;
		cout << istk.top() << endl;
		istk.pop();
		cout << istk.top() << endl;
	}
	catch (exception const& ex){
		cerr << "Exception:" << ex.what() << endl;
		return EXIT_FAILURE;
	}

	system("pause");
	return 0;
}

5、使用字符串作爲函數模板的實參

#include<iostream>
#include<string>
using namespace std;

template<typename T>
T const& Max(T const& a, T const& b){
	return a < b ? b : a;
}

int main(){
	string s = "abc";

	cout << Max("apple", "peach") << endl;
	//cout << Max("apple", "tomato") << endl;//錯誤,不同類型的實參
	//cout << Max("apple", s) << endl;//錯誤,不同類型的實參

	system("pause");
	return 0;
}

上述例子在VS2013中運行錯誤。

上述例子中後面兩個調用錯誤的問題在於:由於長度的區別,這些字符串屬於不同的數組類型,”apple”和”peach”具有相同的類型char const[6],”tomato”的類型是char const[7],因此只有第一個調用合法。但聲明的是非引用參數,可以使用不同的字符串作爲參數。

#include<iostream>
#include<string>
using namespace std;

template <typename T>
T Max(T a, T b){
	return  a < b ? b : a;
}

int main(){
	string s = "abc";

	cout << Max("apple", "peach") << endl;
	cout << Max("apple", "tomato") << endl;//正確,退化爲相同的類型
	//cout << Max("apple", s) << endl;//錯誤,不同類型的實參

	system("pause");
	return 0;
}

上述第二個調用正確,原因是對於非引用類型的參數,在實參演繹的過程中,會出現數組到指針的類型轉換。但是這裏比較的是指針,而不是兩個字符串的字典序。


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