模板声明 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. python pyqtgraph 保存图片到本地

    pyqtgraph官方给的示例居然会报错2333 官方文档传送门:#####pyqtgraph export pyqtgraph支持在可视化窗口中右键保存(Exporting from the GUI ...

  2. vue2 + typescript2 自定义过滤器

    1.定义一个过滤器 // color-directive.ts import { DirectiveOptions } from 'vue' const directive: DirectiveOpt ...

  3. Atitit.ati&#160;&#160;str&#160;&#160;字符串增强api

    Atitit.ati  str  字符串增强api 1. java StringUtils方法全览 分类: Java2011-11-30 17:22 8194人阅读 评论(2) 收藏 举报 javas ...

  4. 小数运算需要注意什么? 接口和抽象类 WinForm窗体上两个panel,怎么实现一个panel固定漂浮在另一个panel之上

    小数运算需要注意什么? 1. 生活中0.1+0.2=0.3, 计算机中可不是这样,为什么呢? 大家都知道计算机类型都是有数据范围的.整形int范围是 正负21亿左右,小数类型同样也是有范围的,但是即使 ...

  5. Python 模块之 ConfigParser: 用 Python 解析配置文件

    在程序中使用配置文件来灵活的配置一些参数是一件很常见的事情,配置文件的解析并不复杂,在 Python 里更是如此,在官方发布的库中就包含有做这件事情的库,那就是 ConfigParser,这里简单的做 ...

  6. Linux free显示讲解

    http://www.cnblogs.com/coldplayerest/archive/2010/02/20/1669949.html 解释一下Linux上free命令的输出. 下面是free的运行 ...

  7. [笔记] 精通正则表达式/Mastering Regular Expressions

    / 匹配<emphasis>这个tag标注的IP地址的RE:‘<emphasis>([0-9]+(\.[0-9]+){3})</emphasis>' / 锚定--a ...

  8. 在Fedora 25中更换openjdk为oracle jdk

    本文修改自csdn: openjdk的好处是: 1.升级方便,fedora团队社区负责维护升级,安全稳定,质量有保证. 2.已经支持了很多应用:而且还越来越强大 3.支持eclipse开发. 实际上, ...

  9. hessian实战1

    服务端: 1.新建MAVEN HessianServer 项目 2.新建接口 Basic public interface Basic { String hello(String name); Str ...

  10. C++算法之 一句话推断一个整数是不是2 的整数次方

    思路:一个整数假设是2的整数次方,那么它的二进制表示中有且仅仅有一位是1,而其它全部位都是0.把这个整数与这个整数减去1之后进行与运算.那么这个整数其中唯一的 1会变为0,这个整数也变为0: 代码: ...