15.6 模板全特化与偏特化(局部特化)
泛化:模板,可以随便指定类型。
特化: 对特殊的类型(类型模板参数)进行特殊的对待,给他开小灶,给它写适合它的专用代码。
一: 类模板特化
<1>类模板全特化
1>常规全特化
必须先有泛化版本,才能存在特化版本。只要涉及特化,一定先存在泛化。
特化版本代码编译器会优先选择。
TC<char, int> tcchar;
tcchar.functest(); //泛化版本
TC<int, int> tcdint;
tcdint.functest(); //int, int的特化版本
//这种特化版本可以任意多;我们目前是写了两个。
2>特化成员函数而不是模板
TC<double, double> tdbldbl; //泛化版本对象, 调用的是泛化版本的构造函数。
tdbldbl.functest(); //因为我们特化了double, double类型的functest函数,所以这里调用的是特化的functest()函数。
template<typename T, typename U>
struct TC //泛化的TC类模板
{TC(){cout << "TC泛化版本构造函数" << endl;}void functest(){cout << "TC泛化版本" << endl;}
};//当T和U这两个类型模板参数都为int类型时,我们希望做一个特化版本
//全特化:就是所有类型模板参数(这里T和U),都得用具体的类型代表。
template<> //全特化: 所有类型模板参数都用具体类型代表,所以这里的template后边的<>里为空
struct TC<int, int> //上边的T绑定到这里的第一个int,上边的U绑定到这里的第二个int
{TC(){cout << "TC<int, int>的特化版本构造函数" << endl;}//在这里可以对该特化版本做单独处理void functest(){cout << "TC<int, int>的特化版本" << endl;}
};template<> //全特化: 所有类型模板参数都用具体类型代表,所以这里的template后边的<>里为空
struct TC<double, int> //上边的T绑定到这里的第一个double,上边的U绑定到这里的第二个int
{//在这里可以对该特化版本做单独处理void functest(){cout << "TC<double, int>的特化版本" << endl;}
};template<> //全特化
void TC<double, double>::functest()
{cout << "double, double的functest()的特化版本" << endl;
}int main()
{TC<char, int> tcchar;tcchar.functest(); //泛化版本TC<int, int> tcdint;tcdint.functest(); //int, int的特化版本TC<double, double> tdbldbl; //泛化版本对象, 调用的是泛化版本的构造函数。tdbldbl.functest(); //因为我们特化了double, double类型的functest函数,所以这里调用的是特化的functest()函数。return 0;
}
<2>类模板偏特化 (局部特化)
偏特化从两方面说起:一个是从模板参数数量上,一个是从模板参数范围上
1>模板参数数量
TC<double, int, double> tcdi;
tcdi.functest(); //泛化版本
TC<int, int, double> teii;
teii.functest(); //偏特化int, U, double版本
//泛化版本
template <typename T, typename U, typename W> //带三个类型模板参数
class TCP
{public:TCP(){cout << "TCP泛化版本构造函数" << endl;}void functest(){cout << "TCP泛化版本" << endl;}
};//从参数数量上进行偏特化,我们现在绑2个类型模板参数。留1个模板类型参数。
template<typename U> //因为另外两个被我绑定到具体类型,所以这里只剩下一个U类型模板参数了。
struct TCP<int, U, double> //大家注意,这里可以跳着来
{TCP(){cout << "TCP<int, U, double>偏特化版本构造函数" << endl;}void functest(){cout << "TCP<int, U, double>偏特化版本" << endl;}
};int main()
{TCP<double, int, double> tcpdi; //TCP泛化版本构造函数tcpdi.functest(); //TCP泛化版本TCP<int, int, double> tcpii; //TCP<int, int, double>偏特化版本构造函数tcpii.functest(); //TCP<int, int, double>偏特化版本return 0;
}
2>模板参数范围上:int, const int(比int小),
原来T,现在T* (从任意类型T索晓伟指针类型T*)
原来是T,现在T&左值引用,或者现在是T&&(右值引用),都叫范围缩小。
TC td;
td.functest(); //泛化版本
TC<double*> tpd;
tpd.functest(); //T*特化版本
TC<const double*> tpd2;
tpd2.functest(); //T*特化版本
TC td3;
td3.functest(); //const T特化版本
TC<int&> tcyi;
tcyi.functest(); //T&左值引用特化版本
TC<int&&> tcyii;
tcyii.functest(); //T&&右值引用特化版本
局部特化,特化完了之后它本质上还是个模板。全特化,特化完了等于一个具体的类了。
//泛化版本
template <typename T>
struct TC
{void functest(){cout << "泛化版本" << endl;}
};//模板参数范围上的特化版本
template <typename T>
struct TC<const T>
{void functest(){cout << "const T特化版本" << endl;}
};template <typename T>
struct TC<T*> //T*的特化版本,告诉编译器,如果使用指针,就调用这个版本。
{void functest(){cout << "T*特化版本" << endl;}
};template <typename T>
struct TC<T&> //左值引用的特化版本
{void functest(){cout << "T&特化版本" << endl;}
};template <typename T>
struct TC<T&&> //右值引用的特化版本
{void functest(){cout << "T&&特化版本" << endl;}
};int main()
{TC<double> td;td.functest(); //泛化版本TC<double*> tpd;tpd.functest(); //T*特化版本TC<const double*> tpd2;tpd2.functest(); //T*特化版本TC<const double> td3;td3.functest(); //const T特化版本TC<int&> tcyi;tcyi.functest(); //T&左值引用特化版本TC<int&&> tcyii;tcyii.functest(); //T&&右值引用特化版本return 0;
}
二:函数模板特化
<1>函数模板全特化
const char* p = “I love China!”;
int i = 12;
tfunc(p, i); //T = const char * , tmprv = const char * & , U = int , tmprv2 = int&
int i = 12;
double db = 15.8f;
tfunc(i, db);
全特化函数模板实际上等价于实例化一个函数模板,并不是等价于一个函数重载
void tfunc<int, double>(int& tmprv, double& tmprv2){} //全特化,等价于实例化一个函数模板
void tfunc(int& tmprv, double& tmprv2){} //重载函数应该长这样
编译器选择最最合适的:普通优先,特化版本,泛化版本;(优先级顺序排列)
如果你传递个字符串给函数模板
函数模板的特化版本中,如果有数组类型模板参数, 指针类型模板参数。
编译器会认为数组类型模板参数比指针类型模板参数更合适。所以编译器会为你选择数组类型的模板参数的特化版本。
<2>函数模板偏特化
函数模板不能偏特化
//函数模板泛化版本
template<typename T, typename U>
void tfunc(T& tmprv, U& tmprv2)
{cout << "tfunc泛化版本" << endl;cout << tmprv << endl;cout << tmprv2 << endl;
}函数模板偏特化
//template<typename U>
//void tfunc<double, U>(double& tmprv, U& tmprv2) //“tfunc”: 非法使用显式模板参数
//{// //......
//}//全特化版本,T = int, U = double
template<>
void tfunc(int& tmprv, double& tmprv2)
{cout << "-------------begin---------------" << endl;cout << "tfunc全特化版本int, double" << endl;cout << tmprv << endl;cout << tmprv2 << endl;cout << "-------------end---------------" << endl;
}//重载函数
void tfunc(int& tmprv, double& tmprv2)
{cout << "tfunc重载函数(int, double)" << endl;
}int main()
{const char* p = "I love China!";int i1 = 12;tfunc(p, i1); //T = const char * , tmprv = const char * & , U = int , tmprv2 = int&int i2 = 12;double db = 15.8f;tfunc(i2, db);return 0;
}
三: 模板特化版本放置位置建议
模板定义、实现都放在一个 .h中;
模板的特化版本和模板的泛化版本都应该放在同一个 .h 文件中。
.h 文件中前面放泛化版本,后面放特化版本。
15.6 模板全特化与偏特化(局部特化)相关推荐
- [C++基础]034_C++模板编程里的主版本模板类、全特化、偏特化(C++ Type Traits)
http://www.cnblogs.com/alephsoul-alephsoul/archive/2012/10/18/2728753.html 1. 主版本模板类 首先我们来看一段初学者都能看 ...
- 模板特化,全特化,偏特化,全部特化,部分特化的含义
模板特化,任何针对模板参数进一步进行条件限制设计的特化版本.<泛型思维> 全特化就是全部特化,即针对所有的模板参数进行特化.<c++ primer> 偏特化就是部分特化,即针对 ...
- 第十天2017/04/21(2、泛型编程:模板 / 全特化、偏特化)
1.什么是模板? template<class T1,class T2,.....> 类属----类型参数化,又称参数模板使得程序可以从逻辑功能上抽象,把被处理的对象(数据)的类型作为参数 ...
- (函数/类模板)的(偏特化/全特化)
特化的概念 特化,就是将泛型的东东搞得"具体化"一些,从字面上来解释,就是为已有的模板参数进行一些使其特殊化的指定,使得以前不受任何约束的模板参数,或受到特定的修饰或完全被指定了下 ...
- C/Cpp / STL / 模板全特化和偏特化
栗子 #include <iostream>template <typename T1, typename T2> struct Test {void Print() { st ...
- C++ 模板的全特化与偏特化
模板为什么要特化,因为编译器认为,对于特定的类型,如果你能对某一功能更好的实现,那么就该听你的. 模板分为类模板与函数模板,特化分为全特化与偏特化.全特化就是限定死模板实现的具体类型,偏特化就是如果这 ...
- Th4.6:模板全特化、偏特化(局部特化)详述
本小节回顾的知识点分别是模板全特化.偏特化(局部特化). 今天总结的知识分为以下4个大点: (1)特化与泛化 (2)类模板特化 (2.1)类模板全特化 a)常规全特化 ...
- C++ 模板 全特化与偏特化
C++ 模板 全特化与偏特化 模板 模板定义:模板就是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数, 从而实现了真正的代码可重用性.模版可以分为两类,一个是函数模版,另外一个是 ...
- C++模板的全特化和偏特化
C++模板的全特化与偏特化 全特化 偏特化 例子 总结 全特化 全特化一般用于处理有特殊要求的类或者函数,此时依靠泛型模板无法处理这种情况.,因此全特化可以运用在类模板和函数模板当中.其模板参数列表为 ...
- 【C++模板】特化与偏特化 template [partial] specialization
1 template specialization 模板特化 一般情况下类模板定义如下: template<class Window, class Controller> class Wi ...
最新文章
- asp.net读取模版并写入文本文件
- 算法导论之用于不相交集合的数据结构
- Spring MVC如何接收浏览器传递来的请求参数--request--形参--实体类封装
- Pandas学习笔记1(序列部分)
- 一次“背锅”和“解锅”后的反思
- PCL .stl格式转成.pcd格式点云文件
- 电驴v1.2.2.45574最新版官方下载
- Java的getbytes()方法使用
- apple id两步验证服务器,【安全可靠】Apple ID 两步验证支持中国地区 - 爱应用
- 地理坐标系:WGS84和BD09互转
- Perfmon监控Windows进程性能
- 【MOOC】计算机网络与通信技术笔记(北交)(1)概述
- 什么是yum源,yum的工作原理又是什么
- python报错(一):takes no arguments
- 关于java中的finalize()方法
- creator 物理画线
- MBA不修“内功”,智能音箱犯后遗症
- NGS_RNA-Seq
- Unity-动画-动画回调函数接口StateMachineBehaviour
- echarts 如何在地图组件上加入南海
热门文章
- 2022-11-18 mysql列存储引擎-assert failed on i < m_idx.size() at rc_attr.h:342-问题分析
- 7-19 统计人数(2008慈溪) (100分)
- 软件测试系列——冒烟测试
- 追梦算法网----团队数量
- html内嵌式选择器,CSS样式 CSS选择器(Cascading Style Sheet)
- 线程2--主线程(main线程)
- 神经网络第一篇——感受野的学习、计算与思考
- 计算机excel感叹号,excel的文件上有个的感叹号是什么意思?
- java mvc外文文献_java spring英文文献和中文翻译
- 小视频如何伪原创 抖音合并视频md5