深入C++之函數模板

深入C++之函數模板

[原創] zengyi820 2003-07-01
第十章 函數模板
Chapter 10 Function template

本章要點概述:
1.什麼是模板(what a function template is)
2.定義和使用模板(how to define and use a function template)
3.函數模板的推演過程(template argument deduction)
4.引用模板實例時如何指定顯示模板參數(how explicit template arguments can be specified when referring to a function template instantiation)
5.編譯器模板的初始化以及對程序組織的要求(how the compiler instantiates templates and the requirements this imposes on the organization of our programs)
6.定義函數模板實例的特化版本(how to define a specialization for a function template instantiation)
7.函數模板的重載及其解析過程如何工作(how function templates can be overloaded and how overload resolution involving function templates works)
8.函數模板定義中的名字解析(name resolution in function template definitions)
9.函數模板定義在名字空間中的方式(how function templates can be defined in namespaces)
10.1函數模板的定義(Function Template Definition)
(1)由強類型語言需求引出的問題:
強類型語言需要我們對不同的類型參數定義不同類型的函數
int min( int a, int b )
{
?? return a < b ? a : b;
}

double min( double a, double b ) {
return a < b ? a : b;
}
??
我們嘗試用預處理器的宏擴展設施解決這個問題
#define min(a,b) ((a) < (b) ? (a) : (b))

這樣的工作機制存在問題:我們來解析一下,預處理器的宏擴展設施的工作機制不是對函數的調用,而是簡單的提供參數的替換,兩個參數值被計算了兩次,一次是比較a,b。一次是宏的返回值計算。
??使用函數模板保留了函數定義和函數調用的語義(函數調用之前實參只被計算一次),其核心算法的功能是:程序員可以對函數接口的全部或者部分類型進行參數化,而函數體保持不變。
(2)函數模板的構造準則(The Principle of Function Template Creation)
函數的實現在一組實例上保持不變,每個實例都處理一種唯一的數據類型,這樣的函數就可以構造成函數模板
template
Type min( Type a, Type b ) {
return a < b ? a : b;
}
int main() {
// ok: int min( int, int );
min( 10, 20 );
// ok: double min( double, double );
min( 10.0, 20.0 );
return 0;
}

(3)函數模板的定義(Function Template Definition)
template總是放在模板定義與聲明的最前面
<>中的是模板參數表,不可爲空,模板參數有兩類:
模板類型參數(template type parameter list):由關鍵字class或typename(在函數模板的參數表中兩者意義相同)後加一個標識符構成。標識符(如上面的Type)可以是任何名字。
模板實例化時,實際的內置或用戶定義類型將替換模板的類型參數。模板類型參數用來聲明變量和強制類型轉換。有效的模板實參類型:int、double、char*、vector或list*
模板非類型參數(template nontype parameter):由一個普通的參數聲明構成,代表了一個潛在的值,該值是模板定義中的一個常量
template
Type min( Type (&arr) [size] );
Size就是該函數模板的非類型參數,代表arr指向的數祖的長度,函數min()實例化時,size將被編譯時已知的常量值替代。模板非類型參數常用在數組聲明中指定數組的大小或者是作爲枚舉常量的初始值
調用函數和取函數地址是函數的兩種使用方法
(4)函數模板定義中應注意的若干問題
a.如果在全局域中聲明瞭與模板參數同名的對象、函數或類型,則該全局名將被隱藏,如下程序段:
typedef double Type;
template
Type min( Type a, Type b )
{
Type tmp = a < b ? a : b; // tmp 類型爲模板參數 Type,而不是全局的typedef
return tmp;
}

b.在函數模板定義中聲明的對象或類型不能與模板參數同名
template
Type min( Type a, Type b ){
typedef double Type; // 這裏就重新聲明瞭模板參數,所以是個錯誤
Type tmp = a < b ? a : b;
return tmp;
}

c.模板類型參數名可以被用來指定函數模板的返回值
template
T1 min( T2, T3 );

T1指明瞭函數min()返回值的類型,T2和T3指明的是參數的類型
d.模板參數名在同一模板中不可重名,但是在不同的函數模板聲明中就可以重複的使用。
e.每個模板類型參數都必須有關鍵字typename或者class在前面,兩者可以互換。
f.模板函數被聲明爲inline或extern的格式:指示符要放在參數表的後面
正確:
template
inline
Type min( Type, Type );

錯誤:
inline
template
Type min( Array, int );
下面我們來看經典教材C++ Primer當中的兩個練習以加深鞏固.
指出下列函數模板的定義哪些是錯誤的,哪些是這確的,並將其改正
(a) template
void foo( T, U, V );

模板的定義應該爲template ,依據:每個模板類型參數都必須有關鍵字typename或者class在前面,兩者可以互換。
(b) template
T foo( int *T );

正確
(c) template
T1 foo( T2, T3 );

正確
(d) inline template
T foo( T, unsigned int* );

應該爲:
template
inline
T foo( T, unsigned int* );

指示符:模板函數被聲明爲inline或extern的格式時指示符要放在參數表的後面
(e) template
void foo( myT, myT );

模板參數名在同一模板中不可重名。
可以改爲:
template
void foo( myT, myT );
(f) template
foo( T, T );

正確
(g) typedef char Ctype;
template
Ctype foo( Ctype a, Ctype b );

正確
練習10.2 下列模板重複聲明中哪些是錯誤的,爲什麼
(a) template
Type bar( Type, Type );
template
Type bar( Type, Type );
(b) template
void bar( T1, T2 );
template
void bar( C1, C2 );

兩個都是正確的
發佈了23 篇原創文章 · 獲贊 2 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章