C++模板詳解(二)
轉載自:http://www.cnblogs.com/gw811/archive/2012/10/25/2736224.html
C++模板
四、類模板的預設模板型別形參
1、可以為類模板的型別形參提供預設值,但不能為函式模板的型別形參提供預設值。函式模板和類模板都可以為模板的非型別形參提供預設值。
2、類模板的型別形參預設值形式為:template<class T1, class T2=int> class A{};為第二個模板型別形參T2提供int型的預設值。
3、類模板型別形參預設值和函式的預設引數一樣,如果有多個型別形參則從第一個形參設定了預設值之後的所有模板形參都要設定預設值,比如template<class T1=int, class T2>class A{};
4、在類模板的外部定義類中的成員時template 後的形參表應省略預設的形參型別。比如template<class T1, class T2=int> class A{public: void h();}; 定義方法為template<class T1,class T2> void A<T1,T2>::h(){}。
定義類模板型別形參:
演示例項1:
TemplateDemo.h
1 #ifndef TEMPLATE_DEMO_HXX
2 #define TEMPLATE_DEMO_HXX
3
4 template<class T> class A{
5 public:
6 T g(T a,T b);
7 A();
8 };
9
10 #endif
TemplateDemo.cpp
1 #include<iostream.h>
2 #include "TemplateDemo.h"
3
4 template<class T> A<T>::A(){}
5
6 template<class T> T A<T>::g(T a,T b){
7 return a+b;
8 }
9
10 void main(){
11 A<int> a;
12 cout<<a.g(2,3)<<endl;
13 }
執行結果: 5
類模板的預設模板型別形參示例1:
TemplateDemo03.h
1 #ifndef TEMPLATE_DEMO_03
2 #define TEMPLATE_DEMO_03
3 //定義帶預設型別形參的類模板。這裡把T2預設設定為int型。
4 template<class T1,class T2=int> class CeilDemo{
5 public:
6 int ceil(T1,T2);
7 };
8 //在類模板的外部定義類中的成員時template 後的形參表應省略預設的形參型別。
9 template<class T1,class T2>
10 int CeilDemo<T1,T2>::ceil(T1 a,T2 b){
11 return a>>b;
12 }
13
14 #endif
TemplateDemo03.cpp
1 #include<iostream.h>
2 #include "TemplateDemo03.h"
3
4 void main(){
5 CeilDemo<int> cd;
6 cout<<cd.ceil(8,2)<<endl;
7 }
執行結果: 2
在類模板的外部定義類中的成員時template 後的形參表應省略預設的形參型別,如果沒有省略,不會出現編譯錯誤而是提出警告:
1 --------------------Configuration: TemplateDemo03 - Win32 Debug--------------------
2 Compiling...
3 TemplateDemo03.cpp
4 g:\c++\cdaima\templatedemo03\templatedemo03.h(12) :
5 warning C4519: default template arguments are only allowed on a class template; ignored
6
7 TemplateDemo03.obj - 0 error(s), 1 warning(s)
原作者:類模板型別形參預設值和函式的預設引數一樣,如果有多個型別形參則從第一個形參設定了預設值之後的所有模板形參都要設定預設值,比如template<class T1=int, class T2>class A{};就是錯誤的,因為T1給出了預設值,而T2沒有設定。
例項測試如下:
類模板的預設模板型別形參示例2:
TemplateDemo03.h
1 #ifndef TEMPLATE_DEMO_03
2 #define TEMPLATE_DEMO_03
3
4 template<class T1=int,class T2,class T3> class CeilDemo{
5 public:
6 int ceil(T1,T2,T3);
7 };
8
9 template<class T1,class T2,class T3>
10 int CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){
11 return a+b+c;
12 }
13
14 #endif
TemplateDemo03.cpp
1 #include<iostream.h>
2 #include "TemplateDemo03.h"
3
4 void main(){
5 CeilDemo<int,int> cd;
6 cout<<cd.ceil(2,3,4)<<endl;
7 }
執行結果: 9
上例中我們看到,雖然多個型別形參則從第一個形參T1設定了預設值為int型別,但後面的兩個並沒有設定預設值。我們在宣告物件的時候指明瞭T2和T3的型別都為int型別,編譯、執行沒有任何警告和錯誤。但並不能否定原作者是錯的,這只是一個特例,看下面的示例:
類模板的預設模板型別形參示例3:
TemplateDemo03.h
1 #ifndef TEMPLATE_DEMO_03
2 #define TEMPLATE_DEMO_03
3
4 template<class T1=int,class T2,class T3> class CeilDemo{
5 public:
6 double ceil(T1,T2,T3);
7 };
8
9 template<class T1,class T2,class T3>
10 double CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){
11 return a+b+c;
12 }
13
14 #endif
TemplateDemo03.cpp
1 #include<iostream.h>
2 #include "TemplateDemo03.h"
3
4 void main(){
5 CeilDemo<double,double> cd;
6 cout<<cd.ceil(2,3.1,4.1)<<endl;
7 }
編譯錯誤:
1 --------------------Configuration: TemplateDemo03 - Win32 Debug--------------------
2 Compiling...
3 TemplateDemo03.cpp
4 g:\c++\cdaima\templatedemo03\templatedemo03.h(12) :
5 error C2244: 'CeilDemo<T1,T2,T3>::ceil' : unable to resolve function overload
6 g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) :
7 error C2065: 'cd' : undeclared identifier
8 g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) :
9 error C2228: left of '.ceil' must have class/struct/union type
10 Error executing cl.exe.
11
12 TemplateDemo03.obj - 3 error(s), 0 warning(s)
從上面的例子我們可以看出,當我們試圖把T2和T3定義為double型別就會出現錯誤(T1預設定義的是int型別)。那是不是我們按照作者所說把T2和T3也設定為預設值double,是否還會出現錯誤?看下面的示例:
類模板的預設模板型別形參示例4:
TemplateDemo03.h
1 #ifndef TEMPLATE_DEMO_03
2 #define TEMPLATE_DEMO_03
3
4 template<class T1=int,class T2=double,class T3=double> class CeilDemo{
5 public:
6 double ceil(T1,T2,T3);
7 };
8
9 template<class T1,class T2,class T3>
10 double CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){
11 return a+b+c;
12 }
13
14 #endif
TemplateDemo03.cpp
1 #include<iostream.h>
2 #include "TemplateDemo03.h"
3
4 void main(){
5 CeilDemo<int,double,double> cd;
6 cout<<cd.ceil(2,3.1,4.1)<<endl;
7 }
編譯錯誤:
--------------------Configuration: TemplateDemo03 - Win32 Debug--------------------
Compiling...
TemplateDemo03.cpp
g:\c++\cdaima\templatedemo03\templatedemo03.h(12) :
error C2244: 'CeilDemo<T1,T2,T3>::ceil' : unable to resolve function overload
g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) :
error C2065: 'cd' : undeclared identifier
g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) :
error C2228: left of '.ceil' must have class/struct/union type
Error executing cl.exe.
TemplateDemo03.obj - 3 error(s), 0 warning(s)
從結果我們可以看出,和上例是一樣的錯誤。從例項中我們可以總結如下:類模板如果有多個型別形參,如果使用型別形參預設值則儘量放在引數列表的末尾,而且預設的引數型別必須相同。如果從第一個形參設定了預設值之後的所有模板形參都要設定和第一個形參同類型的預設值。(宣告:本人也是剛接觸C++,以上只是我經過例項演示對原作者提出的一些質疑,可能我的示例有不到之處,還望大神們不吝賜教,共同完善此部落格,給像我一樣的菜鳥提供一個學習的平臺!)
接下來驗證“不能為函式模板的型別形參提供預設值”:
類模板的預設模板型別形參示例5:
TemplateDemo04.cpp
1 #include<iostream.h>
2
3 template<class T1,class T2,class T3>
4 T1 sum(T1 a,T2 b,T3 c=int){
5 return a+b+c;
6 }
7
8 void main(){
9 cout<<sum<double,double>(1.1,2.1,3)<<endl;
10 }
編譯錯誤:
1 --------------------Configuration: TemplateDemo04 - Win32 Debug--------------------
2 Compiling...
3 TemplateDemo04.cpp
4 g:\c++\cdaima\templatedemo04\templatedemo04.cpp(4) :
5 error C2062: type 'int' unexpected
6 Error executing cl.exe.
7
8 TemplateDemo04.obj - 1 error(s), 0 warning(s)
更改之後的TemplateDemo.cpp
1 #include<iostream.h>
2
3 template<class T1,class T2,class T3>
4 T1 sum(T1 a,T2 b,T3 c){
5 return a+b+c;
6 }
7
8 void main(){
9 cout<<sum<double,short,int>(1.1,3,257)<<endl;
10 }
執行結果: 261.1
原作者演示例項如下:
1 類模板非型別形參示例 2 //模板的宣告或定義只能在全域性,名稱空間或類範圍內進行。即不能在區域性範圍,函式內進行,比如不能在main函式中宣告或定義一個模板。 3 //類模板的定義 4 template<class T>class A{public:T g(T a, T b); A();}; //定義帶有一個類模板型別形參T的類A 5 template<class T1,class T2>class B{public:void g();}; //定義帶有兩個類模板型別形參T1,T2的類B 6 //定義類模板的預設型別形參,預設型別形參不適合於函式模板。 7 template<class T1,class T2=int> class D{public: voidg();}; //定義帶預設型別形參的類模板。這裡把T2預設設定為int型。 8 //template<class T1=int, class T2>class E{}; //錯誤,為T1設了預設型別形參則T1後面的所有形參都必須設定認默值。 9 10 //以下為非型別形參的定義 11 //非型別形參只能是整型,指標和引用,像double,String, String **這樣的型別是不允許的。但是double &,double *物件的引用或指 12 針是正確的。 13 template<class T1,int a> class Ci{public:void g();}; //定義模板的非型別形參,形參為整型 14 template<class T1,int &a>class Cip{public:void g();}; 15 template<class T1,A<int>* m> class Cc{public:void g();}; //定義模板的模板型別形參,形參為int型的類A的物