模版不是類或函數,它們是c++編譯器指令,它只是一個用於生成類或函數的方案,說明如何生成類或函數。 具體生成時,稱爲實例化(instantiation)或具體化(specialization)。因此,模版不能單獨編譯,必須與特定的實例化請求一起使用。最簡單的辦法就是將所有模版信息放入一個頭文件裏,使用時include這個頭文件。如果編譯器支持export關鍵詞,則可以將“類模版”的聲明與定義分開存放在.h和.cpp中。
1. 函數模版的重載(利用可以重載的特徵標)
void Swap(Any& a, Any& b);
//override
template <class Any>
void Swap(Any* a, Any* b, int n);
template <class Any>
void Swap(Any& a, Any& b)
{
Any temp; temp = a; a = b; b = temp;
}
template <class Any>
void Swap(Any* a, Any* b, int n)
{
Any temp;
for (int i = 0; i < n; i++)
{ temp = a[i]; a[i] = b[i]; b[i] = temp; }
}
2. 函數模版的顯式實例化,即可以命令編譯器直接創建 template<class Any> 的實例,把 class Any 實例化。
template void Swap<int>(int&, int&);
template void Swap<Cjob>(Cjob&, Cjob&);
3. 函數模版的顯式具體化,它不使用模版來生成函數定義,而應使用獨立的、專門的函數定義。顯式具體化要有自己的函數定義,而顯式實例化則不需要,這是兩者本質的區別。兩者的相同之處是:都生成了一個具體的函數,而不再是模板。
template <> void Swap<Cjob>(Cjob& a, Cjob& b);
template <> void Swap(Cjob&a, Cjob& b);
template <> void Swap<Cjob>(Cjob& a, Cjob& b)
{
string tStr;
tStr = a.name;
a.name = b.name;
b.name = tStr;
}
template <> void Swap(Cjob& a, Cjob& b)
{
string tStr;
tStr = a.name;
a.name = b.name;
b.name = tStr;
}
4. 函數模版的部分具體化,部分具體化與顯式具體化的區別在於:前者還是一個函數模板,而後者則已經是一個函數。前者的函數定義中,必然還有typename類型待定,這個類型將在函數模板被調用的時候得到“隱式”的具體化。
void Swap(T1& a, T2& b, T3& c);
//explicit specialization
template <class T1, class T2> void Swap<T1, T2, int>(T1& a, T2& b, int& c);
//部分具體化,可以引入各種限制
template <class T1, class T2> void Swap<T1,T2, T2>(T1& a, T2& b, T2& c);
tempate <class T1> void Swap<T1, T1*, T1*>(T1& a, T1* &b, T1* &c);
template <class T1, class T2, class T3>
void Swap(T1& a, T2& b, T3& c)
{
..............
}
template <class T1, class T2> void Swap<T1, T2, int>(T1& a, T2&b, int& c)
{
..............
}
{
.............
}
template <class T1> void Swap<T1, T1*, T1*>(T1 &a, T1* &b, T1* &c)
{
..............
}
5. 類模版之內與之外:在之內聲明時可以忽略類型,之外必須Stack<Type>帶上類型。
class Stack
{
public:
Stack& operator= (const Stack& st);
}
template <class Type>
Stack<Type> & Stack<Type> :: operator=(const Stack<Type>& st)
{
}
6. 類模版的默認類型參數,不能爲函數模版提供默認的類型參數。
class Topo
{
........
};
7a. 類模板的顯式實例化
class SortedArray
{
public:
T val
};
template class SortedArray<int>;
main ( )
{
SortedArray<int> sa; //模板類與模板函數的區別在於:前者被調用時,總是要帶有<parameter-type>,而後者則不帶。因爲後者可以從形式參數來實例化或具體化模板;而前者則只能靠這個後綴,由編譯器決定生成哪種類型。(即使已經顯式實例化了,也要帶上後綴。)
}
7b. 類模板的顯式具體化
class SortedArray
{
........
};
//顯式具體化,定義新的類功能。
template <> class SortedArray<specialized-type-name>
{
........
};
7c. 類模版的部分具體化
class SortedArray
{
public:
SortedArray()
{
printf("1 ");
}
T1 val1;
T2 val2;
T3 val3;
};
template <class T1, class T2>
class SortedArray<T1, T2, T2>
{
public:
SortedArray()
{
printf("2 ");
}
T1 val1;
T2 val2;
};
template <class T1>
class SortedArray<T1, T1, T1>
{
public:
SortedArray()
{
printf("3 ");
}
T1 val;
};
template <>
class SortedArray<int, int, int>
{
public:
SortedArray()
{
printf("4 ");
}
};
int main(int argc, char* argv[])
{
SortedArray<int, int, int> sa1;
SortedArray<int, int> sa2;
SortedArray<int> sa3;
//SortedArray sa4;
printf("Hello World! ");
return 0;
}
8. 模版作爲模版類的成員
class beta
{
private:
template <typename V>
class hold;
hold<T> q;
hold<int> n;
public:
template<typename U>
U blab(U u, T t);
};
//member define
template <typename T>
template <typename V>
class beta<T>::hold
{
private:
V val;
public:
V Value() const {return val;}
};
template <typename T>
template <typename U>
U beta<T>::blab(U u, T t)
{
........
};
9. 模版作爲模版的參數,vc++不支持這種使用,g++支持。
class Stack
{
....
};
template <template <typename T> class Thing>
class Crab
{
....
};
main()
{
Crab<Stack> vStack;
}
10. 模版類的非模版友元函數
class HasFriend
{
public:
HasFriend(const T& i) : item(i) { ct++; }
~HasFriend() { ct--; }
friend void counts();
friend void report(HasFriend<T> &);
private:
T item;
static int ct;
};
void counts()
{
// 每個類有獨立的static變量,模版沒有static變量,因爲模版只是提供給編譯器的方案,本身並不是類。只有模版實例化或具體化之後,纔可以訪問其static變量。
cout << "HasFriend<int>: " << HasFriend<int>::ct;
cout << "HasFriend<double>:" << HasFriend<double>::ct;
}
// 必須爲每個類提供相應的友元。
void report(HasFriend<int> & hf)
{
cout << hf.itme;
}
void report(HasFriend<double> & hf)
{
cout << hf.item;
}
main()
{
HasFriend<int> hf1;
counts();
HasFriend<double> hf2;
counts();
report(hf2);
}
10. 模版類的約束模版友元。
template <typename T> void counts();
template <typename T> void report(T&);
template <typename TT>
class HasFriendT
{
public:
HasFriendT(const TT& i) : item(i) { ct++; }
~HasFriendT() { ct--; }
//在類裏再次聲明爲友元,這裏也是某種程度上的實例化,
//但還沒有徹底實例化,函數還是模版。
friend void counts<TT> ();
friend void reports<HasFriendT<TT> > (HasFriendT<TT>&);
//這裏也可以寫做:
//friend void reports<> (HasFriendT<TT>&);
//讓編譯器自己判斷模版的參數類型!
private:
TT item;
static int ct;
};
template <typename T>
int HasFriendT<T>::ct = 0;
template <typename T>
void counts()
{
//這裏並不是要輸出模版的大小、模版的static成員變量。因爲程序運行時,並不存在模版的實體,
//都是實例化後的確確實實存在的類。因此,這裏指的實例化的類。
cout << "template size: " << sizeof(HasFriendT<T>) << "; ";
cout << "template counts(): " << HasFriendT<T>::ct << endl;
}
template <typename T>
void report(T& hf)
{
cout << hf.item << endl;
}
int main()
{
counts<int>(); //隱式實例化counts,由模版函數變爲具體的函數
HasFriendT<int> hfi1(10); //隱式實例化類,並定義該實例化類的一個對象
HasFriendT<int> hfi2(20);
HasFriendT<double> hfdb(10.5);
report(hfi1); //通過調用,隱式實例化函數
report(hfi2);
report(hfdb);
return 1;
}
11. 模版類的非約束模版友元。
class ManyFriend
{
public:
ManyFriend(const T& i) : item(i) {}
template <typename C, typename D> friend void show2(C&, D&);
private:
T item;
};
template <typename C, typename D>
void show2(C& c, D& d)
{
cout << c.item << ", " << d.item << endl;
}
int main()
{
ManyFriend<int> hfi1(10);
ManyFriend<int> hfi2(20);
ManyFriend<double> hfdb(10.5);
cout << "hfi1, hfi2: ";
show2(hfi1, hfi2);
cout << "hfdb, hfi2: ";
show2(hfdb, hfi2);
return 0;
}