天天看點

未解決-深入C++之函數模闆

http://blog.csdn.net/wohao2000/archive/2004/08/21/80644.aspx

第十章 函數模闆

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 );

兩個都是正确的  

繼續閱讀