模板声明 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. struct job
  3. {
  4. char name[40];
  5. double salary;
  6. int floor;
  7. };
  8. template<> void swap<job>(job &j1, job &j2);
  9. void Show(job &j);
  10. int main(){
  11. using namespace std;
  12. template void swap<job>(job &, job &);
  13. int i = 10, j = 20;
  14. swap(i, j);
  15. return 0;
  16. }
  17. template<typename Any>
  18. void swap(Any &a, Any &b){
  19. Any temp;
  20. temp = a;
  21. a = b;
  22. b = temp;
  23. }
  24. template<> void swap<job>(job &j1, job &j2){
  25. double temp_sal;
  26. temp_sal = j1.salary;
  27. j1.salary = j2.salary;
  28. j2.salary = temp_sal;
  29. }

隐式实例化

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

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

注意:试图在同一个文件(或转换单元)中使用同一种类型的显示实例化和显示具体化声明,会出错。

推荐:可以用在函数调用时,直接显示实例化,而不使用显示实例化声明。

  如:

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

  

模范代码:

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

C++模板之函数模板实例化和具体化的更多相关文章

  1. C++—模板(1)模板与函数模板

    1.引入 如何编写一个通用加法函数?第一个方法是使用函数重载, 针对每个所需相同行为的不同类型重新实现这个函数.C++的这种编程机制给编程者极大的方便,不需要为功能相似.参数不同的函数选用不同的函数名 ...

  2. C++ 函数重载,函数模板和函数模板重载,选择哪一个?

    重载解析 在C++中,对于函数重载.函数模板和函数模板重载,C++需要有一个良好的策略,去选择调用哪一个函数定义(尤其是多个参数时),这个过程称为重载解析. (这个过程将会非常复杂,但愿不要遇到一定要 ...

  3. C++入门经典-例9.1-函数模板,函数模板的作用,使用数组作为模板参数

    1:函数模板不是一个实在的函数,因此编译器不能为其生成可执行的代码.定义函数模板只是一个对函数功能框架的描述,在具体执行时,将根据传递的实际参数决定其功能. 2:函数模板定义的一般形式如下: temp ...

  4. C++ 模板学习 函数模板、类模板、迭代器模板

    使用模板能够极大到使得代码可重用. 记录一下,方便后续使用. 1. 函数模板,支持多种类型参数 #include <stdio.h> #include <math.h> //函 ...

  5. C++面向对象编程之类模板、函数模板等一些补充

    1.static数据 和 static函数: 对于 非static函数 在内存中只有一份,当类对象调用时,其实会有该对象的this pointer传进去,那个函数就知道要对那个对象进行操作: stat ...

  6. C++_进阶之函数模板_类模板

     C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...

  7. C++模板之隐式实例化、显示实例化、隐式调用、显示调用和模板特化详解

    模板的实例化指函数模板(类模板)生成模板函数(模板类)的过程.对于函数模板而言,模板实例化之后,会生成一个真正的函数.而类模板经过实例化之后,只是完成了类的定义,模板类的成员函数需要到调用时才会被初始 ...

  8. C++基础--函数模板

    函数模板是通用的函数描述,其使用泛型来定义函数.其实就是有些操作,如果撇开具体的变量的数据类型,其操作是一样的如果我们将这些操作写成一个模板,在调用不同变量的时候就设定好变量类型就可了,后续的操作基本 ...

  9. C++进阶-1-模板基础(函数模板、类模板)

    C++进阶 模板 1.1 函数模板 1 #include<iostream> 2 using namespace std; 3 4 // 模板 5 6 // 模板的简单实例 7 // 要求 ...

随机推荐

  1. C#开发ActiveX控件,.NET开发OCX控件案例 【转】

    http://xiaochen.2003.4.blog.163.com/blog/static/480409672012530227678/ 讲下什么是ActiveX控件,到底有什么作用?在网页中又如 ...

  2. SSH 原理和公匙私匙

    先主要介绍了Telnet.SSH 的通信原理,分析了其通信时的工作流程. Telnet 无论Telnet协议连接的是什么类型终端,都会转换为NVT(Net Virtual Terminal)格式进行通 ...

  3. 权重轮询调度算法(WeightedRound-RobinScheduling)-Java实现

    权重轮询调度算法(WeightedRound-RobinScheduling)-Java实现 import java.math.BigInteger; import java.util.ArrayLi ...

  4. chardet的使用

    http://blog.csdn.net/jy692405180/article/details/52496599

  5. odoo 的时差 坑 [updated]

    很多人掉进了odoo的时间坑 odoo约定关于日期的数据,存放在数据库时,以 utc0 时区也就是不带时区存放,应用程序读取日期展示日期时,转换成用户的时区展示.用户的时区通过context传递. o ...

  6. ZipOutputStream 用法 小计

    ZipOutputStream s = new ZipOutputStream(File.Create(ZipedFile)); 构造函数之后 文件就已经创建出来了 只是 0kb s.Write(bu ...

  7. hdu5296(2015多校1)--Annoying problem(lca+一个公式)

    Annoying problem Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others ...

  8. mysql (8.0 或以下)数据 卸载, 安装, 创建用户, 赋权

    卸载 安装 创建用户wmxl create user 'wmxl'@'202.115.253.71' identified by '你的密码' 如果是mysql8.0,再输入以下 ALTER USER ...

  9. 我的Android进阶之旅------&gt;Android中android:windowSoftInputMode的使用方法

    面试题:怎样在显示某个Activity时马上弹出软键盘? 答案:在AndroidManifest.xml文件里设置<activity>标签的android:windowSoftInputM ...

  10. angular.js 入门

    1.安装nodejs 首先要安装nodejs,如果你的电脑已经装过了,最好确认是比较新的版本,否则可能会出问题. 没有安装的直接去nodejs官网下载nodejs安装.安装过程很简单,官网有教程. 安 ...