C++模板之函數模板實例化和具體化

模板聲明 template<typename/class T>,  typename比class最近後添加到C++標準。ios

 

常規模板,具體化模板,非模板函數的優先調用順序。c++

非模板函數(普通函數)> 具體化模板函數 > 常規模板函數

 

顯示具體化:性能

具體化表示爲某一特定的類型重寫函數模板,聲明的含義是使用獨立的,專門的函數定義顯示地爲 特定類型生成函數定義。spa

爲何要有顯示具體化?處理模板函數所不能處理的特殊狀況。顯式具體化顯式具體化也是基於函數模板的,只不過在函數模板的基礎上,添加一個專門針對特定類型的、實現方式不一樣的具體化函數。.net

顯示具體化聲明在關鍵字template後包含<>.c++11

如: code

  1. template<> void swap<job>(job &j1, job &j2);  

vs2013不支持: ci

  1. void swap(Any &a, Any &b);  
  2.   
  3. struct job  
  4. {  
  5.     char name[40];  
  6.     double salary;  
  7.     int floor;  
  8. };  
  9.   
  10. template<> void swap<job>(job &j1, job &j2);  
  11.   
  12. void Show(job &j);  
  13.   
  14. int main(){  
  15.     using namespace std;  
  16.   
  17.     template void swap<job>(job &, job &);  
  18.   
  19.     int i = 10, j = 20;  
  20.       
  21.     swap(i, j);  
  22.   
  23.   
  24.     return 0;  
  25. }  
  26.   
  27.   
  28. template<typename Any>  
  29. void swap(Any &a, Any &b){  
  30.     Any temp;  
  31.     temp = a;  
  32.     a = b;  
  33.     b = temp;  
  34. }  
  35.   
  36. template<> void swap<job>(job &j1, job &j2){  
  37.     double temp_sal;  
  38.     temp_sal = j1.salary;  
  39.     j1.salary = j2.salary;  
  40.     j2.salary = temp_sal;  
  41. }  

隱式實例化

在發生函數模板的調用時,不顯示給出模板參數而通過參數推演,稱之爲函數模板的隱式模板實參調用(隱式調用)。如:get

1

2

3

4

5

template <typename T> void func(T t)

{

      cout<<t<<endl;

}

 func(5);//隱式模板實參調用

  

顯示實例化:

實例:如函數調用swap(i,j)會致使編譯器生成swap()的一個實例,該實例使用 int 類型。

句法:聲明所需的種類用<>符號指示類型,並在聲明前加上關鍵字template:

爲何要有顯示實例化?事實上,編譯器只在要調用函數的時候才使用到函數,若是不使用顯示實例化,每次調用函數時,模板都會消耗性能去推導使用的是哪一個類型的函數,增長了程序運行時的負擔;使用了顯示實例化,則在編譯時就已經處理了函數選擇。

  1. template [函數返回類型] [函數模板名]<實際類型列表>(函數參數列表)

實例化示例:

    1. template void swap<int>(int,  int);  

注意:試圖在同一個文件(或轉換單元)中使用同一種類型的顯示實例化和顯示具體化聲明,會出錯。

推薦:能夠用在函數調用時,直接顯示實例化,而不使用顯示實例化聲明。

  如:

1

2

3

4

5

6

7

8

9

10

11

12

template <typename T>

T add(T x,T y)

{

      return x+y;     

}

int main()

{

     int i1=2,i2=3;

     add<int>(i1,i2);

     template int add<int>(i1,i2);//儘可能用上面一行的寫法代替本行

     return 0;   

}

  

模範代碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

///**********************************************

 /// @file    templetAdd.cc

 /// @author  alex(AlexCthon@qq.com)

 /// @date    2018-06-19 21:42:20

 ///**********************************************/

 

#include <string.h>

#include <iostream>

using std::cout;

using std::endl;

//模板-->類型參數化-->代碼生成器

 

//    實例化(模板參數推導)

//函數模板    -->    模板函數

 

 

//< >  模板參數列表

//一、使用class 或者typename設置類型參數

//二、非類型參數、常量表達式(整型數據)

template <class T>

T add(T x,T y)

{

    return x + y;

}

#if 0

template int add<int>(int x,int y)//

{

    cout<<"template 顯示實例化"<<endl;

    return x+y;

}

#endif

template<> int add<int>(int x,int y)//等價於template<>int add(int x,int y)

{

    cout<<"template 顯示具體化"<<endl;

    return x+y;

}

//模板的特化版本,不能獨立用於通用版本

//針對特殊情形,但必定要在通用版本存在時才能用

template<>//把這行註釋掉也是能夠的,那代表下面的這個方法是重載了模板函數

const char* add(const char*lhs,const char* rhs)

{

    char*tmp = new char[strlen(lhs)+strlen(rhs)+1]();

    strcpy(tmp,lhs);

    strcat(tmp,rhs);

    return tmp;

}

#if 0

//普通函數與函數模板能夠重載

//普通函數優先級高於模板函數

int add(int x,int y)//能夠重載,由於形參類型不同

{

    return x + y;

}

#endif

//函數模板與函數模板之間也能夠重載

//函數模板的聲明

template <typename T>

T add(T x,T y,T z);

 

//c++11的特性

//c++11之前的版本對於函數模板而言,非類型參數不能設置默認值

//非類型參數必須是整形類數據(bool、char、int、long、long long)

template <typename T,int num=10>

int func(T x,T y)

{

    return x*y*num;

}

int main()

{

    int a=3,b=4;

    double c1=1.2,c2=2.3,c3=4.9;

    char ch1='a',ch2=2;

    //template char add<char>(char x,char y);//試圖在同一個文件(或轉換單元)中使用同一種類型的顯示實例化和顯示具體化聲明,會出錯

    func(ch1,ch2);

    const char *p1="hello";

    const char *p2="good";

 

    cout << "int + int = " << add(a,b) << endl;//隱式實例化

    cout << "double + double = " << add<int>(c1,c2) << endl;//顯示實例化

    cout << "char + char = " << add(ch1,ch2) << endl;

    cout << "double + double = " << add(c1,c2,c3) << endl;

    cout << "int + int = " << func<double,8>(a,b) << endl;//常量傳遞的方式

    //cout << "a+d1=" << add(a,c1) << endl;//error,模板參數必須嚴格一致

  

    cout << add(p1,p2) << endl;

    return 0;

}

//函數模板的實現

template <class T>

T add(T x,T y,T z)

{

    return x +y + z;

}

  

總結:

隱式實例化指的是:在使用模板以前,編譯器不生成模板的聲明和定義實例。只有當使用模板時,編譯器才根據模板定義生成相應類型的實例。如:int i=0, j=1;swap(i, j);  //編譯器根據參數i,j的類型隱式地生成swap<int>(int &a, int &b)的函數定義。Array<int> arVal;//編譯器根據類型參數隱式地生成Array<int>類聲明和類函數定義。

顯式實例化:當顯式實例化模板時,在使用模板以前,編譯器根據顯式實例化指定的類型生成模板實例。如前面顯示實例化(explicit instantiation)模板函數和模板類。其格式爲:template typename function<typename>(argulist);template class classname<typename>;顯式實例化只需聲明,不須要從新定義。編譯器根據模板實現實例聲明和實例定義。

顯示具體化:對於某些特殊類型,可能不適合模板實現,須要從新定義實現,此時可使用顯示具體化(explicite specialization)。顯示實例化需從新定義。格式爲:template<> typename function<typename>(argu_list){...};template<> class classname<typename>{...};

相關文章
相關標籤/搜索