測試程式使用namespace
包裹
示例程式碼:
類别範本
可以允許使用者任意指定的部分可以抽出成為模板
template<typename T>
// 使用的時候在指明型別
class complex
{
public:
complex (T r = 0. T i = 0) : re(r), im(i) {}
complex& operator += (const complex&);
T real() const {return re;}
T imag() const {return im;}
private:
T re, im;s
}
函式模板
語法和類别範本一樣
template<typename T>
inline
const T& min(const T& a, const T& b) {return b < a ? b : a;}
// 使用的時候不需要指名型別 -> <符號的本質是運算子過載
stone r1(2, 3), r2(3, 3);
r3 = min(r1, r2);
成員模板
模板裡面的member
,該member
本身又是一個template
-> 模板內的模板 -> 主要用來設計建構函式
示例程式碼:
template<class T1, class T2>
struct pair
{
T1 first;
T2 second;
pair() : first(T1()), second(T2()) {}
pair(const T1& a, const T2& b) : first(a), second(b) {}
// 再設計模板
template<class U1, class U2>
pair(const pair<U1, U2>& p) : first(p.first), second(p.second) { }
};
模板特化
專門針對某一型別設計的函式
示例程式碼:
partial specialization 模板偏特化(個數的偏特化,範圍的偏特化)
個數偏特化:
template<typename T, typename Alloc=...>
class vector
{
}
T
是指定函式型別.Alloc
是指定函式的分配器(標準庫的內容)
c++
當中最小單位是char
型別.八位,如果是bool
型別那麼只佔用一位.那麼就不需要使用泛化
實際上就是在宣告模板的時候指定一個模板的泛化值是什麼(類似宣告形參的時候賦予初始值)
示例程式碼:
template<typename Alloc=...>
class vertor<bool, Alloc>
{
}
範圍上的偏特化
如果設計一個模板特化型別T
,但是他不是一個具體的型別.他是一個指標.指向任意型別.所以T
的範圍就縮小了
示例程式碼:
template<typename T>
class C
{
}
在宣告一個指標的T
template<typename U>
class C<U*>
{
}
如果使用者用的是指標,編譯器會使用下面一套程式碼.如果是指標,那麼編譯器會用上面一套程式碼
T*
表示指向什麼都可以
使用者宣告方式:
c<string> obj1; // 使用上面一個T程式碼
c<string*> obj2; // 使用下面一個U*程式碼
template template parameter模板模板引數
宣告一個模板.有兩個引數.第二個引數也是一個模板
示例程式碼:
目的是為了讓使用者可以指定使用容器來構造類
容器需要指定元素型別和分配器
上面的模板模板宣告完成後具體使用:
// 錯誤使用方式
// XCls<string, list> mylst1; -> list傳入就是第二個Contrainer,會拿前面的T當前元素型別
// 之所以這裡可以這樣使用,是因為元素有第二模板引數.只是有預設值.如果這樣使用語法過不了
// list的特性接收兩個引數
XCls<string, Lst> mylst;
上訴程式碼當中傳入的list
並沒有繫結任何引數,所以它仍然是一個模糊的東西.這樣才可以把它稱之為模板
無法透過的原因是:容器接收好幾個引數
如果只接收一個引數那麼是可以透過的
示例程式碼:
使用方式:
XCls<string, shared_ptr> p1;
// XCls<double, unique_ptr> p2; -> 由於unique_ptr的特性所以上述的宣告方式進行這樣構造是不可以的
非模板模板偏特化:
template<class T, class Sequence = deque<T>>
class stack {
friend bool operator== <> (const stack&, const stack&);
friend bool operator< <> (const stack&, const stack&);
protected:
Sequence c; // 底層容器
};
在這段程式碼當中,由於Sequence
有預設初始值.所以在宣告呼叫的時候有兩種方式:
stack<int> s1;
stack<int, list<int>> s2;
在這個當中如果要修改第二個初始值.需要指定list<int>
並且向list
當中傳入引數.那麼它就不是一個模糊的值.而是一個被定義的值.所以不能視為模板
小結