C++模板之函数模板实例化和具体化

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> hot3.png

模板声明 template<typename/class T>,  typename比class最近后添加到C++标准。

 

常规模板,具体化模板,非模板函数的优先调用顺序。

非模板函数(普通函数)> 具体化模板函数 > 常规模板

 

显示具体化:

具体化表示为某一特定的类型重写函数模板,声明的含义是使用独立的,专门的函数定义显示地为 特定类型生成函数定义。

为什么要有显示具体化?处理模板函数所不能处理的特殊情况。显式具体化显式具体化也是基于函数模板的,只不过在函数模板的基础上,添加一个专门针对特定类型的、实现方式不同的具体化函数。

显示具体化声明在关键字template后包含<>.

如: 

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

vs2013不支持: 

  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. }  

隐式实例化

在发生函数模板的调用时,不显示给出模板参数而经过参数推演,称之为函数模板的隐式模板实参调用(隐式调用)。如:

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;

//模板-->类型参数化-->代码生成器

 

//    实例化(模板参数推导)

//函数模板    -->    模板函数

 

 

//< >  模板参数列表

//1、使用class 或者typename设置类型参数

//2、非类型参数、常量表达式(整型数据)

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>{...};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flybirding10011

谢谢支持啊999

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值