1,多参数类模板:

 1,类模板可以定义任意多个不同的类型参数;

  1,代码示例:

 template <typename T1, typename T2>
class Test
{
public:
void add(T1 a, T2 a);
}; Test<int, float> t;

    2,类模板可以被特化:

    1,指定类模板的特定实现;

    2,部分类型参数必须显示指定;

    3,根据类型参数分开实现类模板;

   3,类模板的特化类型:

     1,部分特化 - 用特定规则约束类型参数;

      1,上面的为部分特化;

      2,完全特化 - 完全显示指定类型参数;

   4,类模板的特化编程实验:

 #include <iostream>
#include <string> using namespace std; template
< typename T1, typename T2 >
class Test
{
public:
void add(T1 a, T2 b)
{
cout << "void add(T1 a, T2 b)" << endl;
cout << a + b << endl;
}
}; /* 关于上述第一个类模板的特殊实现,关于指针的特化实现 */
template
< typename T1, typename T2 >
class Test < T1*, T2* > // 关于指针的特化实现
{
public:
void add(T1* a, T2* b)
{
cout << "void add(T1* a, T2* b)" << endl;
cout << *a + *b << endl;
}
}; /* 定义上述第一个类模板的特殊实现,即当Test 类模板的两个类型参数完全相同时,使用这个实现;编译器并不认为在这里重新定义了一个新的模板,它认为这里是在定义第一个类模板的特殊实现;这里是部分特化;
*/
template
< typename T >
class Test < T, T > // Test 类模板的两个类型参数完全相同时,使用这个实现;
{
public:
void add(T a, T b)
{
cout << "void add(T a, T b)" << endl;
cout << a + b << endl;
} void print() // 特化实现可以重新定义新的函数;
{
cout << "class Test < T, T >" << endl;
}
}; /* 定义上述第一个类模板的特殊实现,当 T1 == void* 并且 T2 == void* 时,使用这个实现; */
template
< > // 没有泛指类型;
class Test < void*, void* > // 当 T1 == void* 并且 T2 == void* 时
{
public:
void add(void* a, void* b)
{
cout << "void add(void* a, void* b)" << endl;
cout << "Error to add void* param..." << endl;
}
}; int main()
{
Test<int, float> t1; // 使用第一个类模板;
Test<long, long> t2; // 使用第三个类模板,特化实现;
Test<void*, void*> t3; // 使用第四个类模板,特化实现; t1.add(, 2.5); // void add(T1 a, T2 b) 3.5; t2.add(, ); // void add(T a, Tb) 10;
t2.print(); // class Test < T, T > t3.add(NULL, NULL); // void add(void* a, void* b);Error to add void* param...; Test<int*, double*> t4; // 未有定义指针特化时,编译器显示 14 行:error: invalid operands of types 'int*' and 'double*' to binary 'operator+';
// 特化指针后,打印 void add(T1* a, T2* b);
int a = ;
double b = 0.1; t4.add(&a, &b); // 1.1 return ;
}

     1,类模板的特化实现表象上面好像定义了不同的类模板,但其实我们仅仅是根据需要将一个类模板分开成不同的情况来实现;

     2,编译器编译过后根据我们使用的类型参数来决定究竟是哪一种实现;

   5,类模板特化注意事项:

     1,特化只是模板的分开实现:

       1,本质上是同一个类模板;

      2,仅仅是将模板根据需要分开来实现;

     2,特化类模板的使用方式是统一的;

      1,必须显示指定每一个类型参数;

2,类模板特化与重定义有区别吗?函数模板可以特化吗?

1,有区别;

3,特化的深度分析:

1,重定义和特化的不同:

 1,重定义:

  1,一个类模板和一个新类(或者两个类模板);

    1,重定义本质是要么是实现了两个类模板,要么是一个类模板加上 一个新的类;

    2,特化本质是只实现同一个类模板,特化的目的仅仅是考虑一些特殊的情况类模板应该如何工作;

   2,使用的时候需要考虑如何选择的问题;

    1,使用的时候没有统一的方式,要选择用类模板的种类或用新的类;

 2,特化:

  1,以统一的方式使用类模板和特化类;

  2,编译器自动优先选择特化类;

    1,能用特化就不要重定义;

2,函数模板只支持类型参数完全特化:

 1,代码示例:

 template < typename T>  // 函数模板定义
bool Equal(T a, T b)
{
return a == b;
} template < > // 函数模板完全特化
bool Equal<void *>(void* a, void* b)
{
return a == b;
}

3,特化的深入理解编程实验:

 #include <iostream>
#include <string> using namespace std; /* 以下是类模板的重定义实现 */
template
< typename T1, typename T2 >
class Test
{
public:
void add(T1 a, T2 b)
{
cout << "void add(T1 a, T2 b)" << endl;
cout << a + b << endl;
}
}; /*
template
< >
class Test < void*, void* > // 当 T1 == void* 并且 T2 == void* 时
{
public:
void add(void* a, void* b)
{
cout << "void add(void* a, void* b)" << endl;
cout << "Error to add void* param..." << endl;
}
};
*/ /* 类模板的重定义,重新实现上面注释的模板特化,处理指针相加 */
class Test_Void
{
public:
void add(void* a, void* b)
{
cout << "void add(void* a, void* b)" << endl;
cout << "Error to add void* param..." << endl;
}
}; /* 以下是函数模板的特化实验 */ template
< typename T >
bool Equal(T a, T b)
{
cout << "bool Equal(T a, T b)" << endl; return a == b;
} /* 函数完全特化解决浮点数比较问题 */
template
< >
bool Equal<double>(double a, double b)
{
const double delta = 0.00000000000001;
double r = a - b; cout << "bool Equal<double>(double a, double b)" << endl; return (-delta < r) && (r < delta);
} /* 直接重载 */
bool Equal(double a, double b)
{
const double delta = 0.00000000000001;
double r = a - b; cout << "bool Equal(double a, double b)" << endl; return (-delta < r) && (r < delta);
} int main()
{
Test<void*, void*> t3; // 这里错误了,要用 Test_Void t3; 这样的 定义方式,因为重定义了类的实现方式,注销了模板特化方式;写代码时,要时刻考虑究竟是要使用类模板 还是要使用新类,这就是弊端,所以能特化时,就不要重新定义、重新实现; cout << Equal( , ) << endl; // bool Equal(T a, T b) 1
cout << Equal<>( 0.001, 0.001 ) << endl; // 用相等符号比较两个浮点数是否相等是有问题的;用了特化后:bool Equal<double>(double a, double b) 1
cout << Equal( 0.001, 0.001 ) << endl; // bool Equal(double a, double b) 1;这里调用全局重载函数,因为编译器会优先寻找全局重载函数; return ;
}

4,工程中的建议:

  1,当需要重载函数模板时,优先考虑使用模板特化;当模板特化无法满足需求,再使用函数重载!

4,小结:

1,类模板可以定义任意多个不同的类型参数;

2,类模板可以被部分特化和完全特化;

3,特化的本质是模板的分开实现;

4,函数模板只支持完全特化;

5,工程中使用模板特化代替类(函数)重定义;

C++中类模板的深入理解的更多相关文章

  1. 结合自己的程序对thinkphp模板常量的理解

    先上个图,有时候路径很多,没理解会搞混,看手册的说明 页面login.html模板的访问路径为http://www.tp.com/index.php/admin/Manager/login,测试他的常 ...

  2. django 模板context的理解

    context作为view与template之间的桥梁,理解它的工作原理对于djagno的模板工作机制至关重要. class ContextDict(dict):#上下文词典,由词典可以通过conte ...

  3. C++中函数模板的深入理解

    1,函数模板深入理解: 1,编译器从函数模板通过具体类型产生不同的函数: 1,模板就是模子,通过这个模子可以产生很多的实物: 2,函数模板就是编译器用来产生具体函数的模子: 2,编译器会对函数模板进行 ...

  4. 关于aspx模板页面元素路径的问题,以及对模板页面的理解

    模板页面仅是模板,它不是单独存在的页面,它的路径就是引用它的内容页面的路径. 换句话说,模板页面,只是内容页面上固定的部分.     模板页面引用了的js和CSS,内容页面就不用重新引用了   css ...

  5. C++中类模板的概念和意义

    1,在 C++ 中是否能够将泛型的思想应用于类? 1,函数模板是将泛型编程的思想应用于函数,就有了函数模板: 2,可以,常用的 C++ 标准库就是 C++ 中的标准模板库,C++ 中的 STL 就是将 ...

  6. 网络流EdmondsKarp算法模板理解

    先推荐一个讲网络流的博客,我的网络流知识均吸收于此   传送门 EdmondsKarp算法基本思想:从起点到终点进行bfs,只要存在路,说明存在增广路径,则取这部分路 权值最小的一部分,即为增广路径( ...

  7. C++模板机制总结

    模板是C++中非常重要的组成部分,之前自己对这块领域一直不太熟悉.最近趁着有时间学习了一下,特此总结. 首先是函数模板,它的定义方式如例子所示: template <typename T> ...

  8. PHP实现简易的模板引擎

    PHP实现简易的模板引擎 1.MVC简介 MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式(详情自己百度): 1. Mode ...

  9. (转)dedecms网页模板编写

    网页模板就是templets中的htm文件,所以编写模板就是要编写html.这篇文章不是关于标签的具体使用,而是对网页模板的一些理解.包括基本的标签语法,封面模板,列表模板和文档模板的关系. 一 关于 ...

随机推荐

  1. jquery 获取多选select的文本中并拼接成字符串

    //拼接产品字符串 var productArray = new Array(); $.each($("#fmeatask-subSystem").find("optio ...

  2. 2. ZooKeeper基础

    1. ZooKeeper的特性 ZooKeeper的特性主要从会话.数据节点,版本,Watcher,ACL权限控制,集群角色这些部分来了解,其中需要重点掌握的数据节点与Watcher 1.1 会话 客 ...

  3. python车牌精确定位

    #coding=utf-8 import cv2 # 使用的是HyperLPR已经训练好了的分类器 watch_cascade = cv2.CascadeClassifier('model/casca ...

  4. zabbix3.4.8配置自动发现主机并监控

    一.       自动发现功能简介 Zabbix服务器端通过网络或者主机名等方式进行客户端的扫描发现,从进行加入到监控的主机队列中,适用于批量加入多主机监控的场景. 二.       自动发现功能实施 ...

  5. python常用函数 I

    iter(iterable) 可以生成一个迭代器. 例子: islice(iterator, int, int) itertools的islice方法为迭代器生成器提供切片操作. 例子: izip_l ...

  6. Center os vi

    vi /etc/virc set nu 设置所有文件显示行号 :1,$s/after/befer/g  全局替换 :%s/after/befer/g 全局替换 yy 复制一行 p 粘贴 yw 复制一个 ...

  7. windows H2database 安装

    转载百度经验 H2是一个开源的.纯java实现的关系数据库,小巧并且使用方便,十分适合作为嵌入式数据库使用 首先打开浏览器进入H2官网http://www.h2database.com/html/ma ...

  8. java生成快递单并调用打印机打印

    生成快递单过程中需要生成条形码,生成条形码可参考:https://www.cnblogs.com/linbky/p/12091248.html 下面这段代码生成的快递单是完全符合京东快递的10 x 1 ...

  9. 微信小程序中显示html富文本的方法

    微信小程序中显示html富文本的方法 使用方法:git地址:https://github.com/icindy/wxParse 一.下载wxParse文件 二.在要引入的页面的js文件中,引入文件 j ...

  10. 命令查看当前运行APP的包名和Activity

    先用usb链接手机 启动要查看的程序,命令查看当前运行的包名和Activity更清晰. 使用adb shell dumpsys window | findstr mCurrentFocus  命令查看 ...