<五>模板的完全特例化和非完全特例化
模板作为C++泛型编程的基础十分重要,其使得一份代码能用于处理多种数据类型。而有些时候,我们会希望对一些特定的数据类型执行不同的代码,这时就需要使用模板特例化(template specialization)。
函数模板特例化
首先说一个重要的,函数模板的特例化并不是函数重载,每一个特例化实际上是提供了另一个模板定义式,因此特例化不影响函数匹配。
特例化一个函数模板时,必须为模板中的每个参数都给出实参,关键字template后跟一个<>
类模板特例化
类模板中,提供所有实参时叫做全特化,类模板的全特化和函数模板的特例化上没有什么不同(除了一个是类模板一个是函数模板:D)
与函数模板必须为每个模板参数提供实参不同,类模板支持部分特例化,也叫偏特化(partial specialization)
当定义类模板的偏特化版本时,模板参数只需包含原模板中那些还未确定类型的模板参数,在类名之后需要添加<>,且需要按对应位置填入实参。
template<typename T, typename P>
class test {
public:
test() { cout << "这是未特化的类模板\n"; }
};
template<typename P>//T被特化为bool类型,template<>中无需typename T
class test<bool,P> {
public:
test() { cout << "这是bool偏特化的类模板\n"; }
};
template<>//全特化,template<>可以为空
class test<int*, int*> {
public:
test(){ cout << "这是接受两个指针类型的全特化的类模板\n"; }
};
{
test<int*, int> t1;//会调用未特化的类模板
test<bool,int> t2;//会调用bool偏特化
test<int*, int*> t3;//全特化版本
}
#include <iostream>
using namespace std;
template<typename T>
class MyVector {
public:
MyVector<T>() { cout << "MyVector<T>()" << endl; }
};
//针对 char * 模板特例化
template<>
class MyVector<char *> {
public:
MyVector() { cout << "MyVector<char *>" << endl; }
};
//模板特例化,只针对指针类型提供的部分特例化,只知道指针,但是什么指针不知道
template<typename Ty>
class MyVector<Ty*> {
public:
MyVector() { cout << "MyVector<Ty *>" << endl; }
};
//template<>
//class MyVector<int(*)(int, int)> {
//public:
// MyVector() { cout << "int (*)(int,int )" << endl; }
//
//};
//template<typename T>
//class MyVector<T(*)(T, T)> {
//public:
// MyVector() { cout << "MyVector<T(*)(T, T)>" << endl; }
//
//};
//
//template<typename R1, typename R2, typename R3>
//class MyVector<R1(*)(R2, R3)> {
// public:
// MyVector() { cout << "MyVector<R1(*)(R2, R3)>" << endl; }
//
//};
//template<typename R1, typename R2, typename R3>
//class MyVector<R1(R2, R3)> {
// public:
// MyVector() { cout << "MyVector<R1(R2, R3)>" << endl; }
//
//};
int sum(int x, int y) {
return x + y;
}
int main() {
MyVector<int> v1; //缺省模板
MyVector<char *> v2;// char * 特例化模板
MyVector<int *> v3;// 使用部分特例化 class MyVector<Ty*>
MyVector<int (*)(int,int)> v4; // 使用部分特例化 class MyVector<Ty*> ,int (*)(int,int) 指向函数的指针
// 如何针对 MyVector<int (*)(int,int)> v4;写一个完全特例化版本? 写法如下
/*
template<>
class MyVector<int(*)(int, int)> {
public:
MyVector() { cout << "int (*)(int,int )" << endl; }
};
*/
// 如何针对 MyVector<int (*)(int,int)> v4;写一个部分特例化版本? 写法如下 两种
/* 写法1
MyVector 元素是函数指针,返回类型是R1,两个参数类型分别是R2,R3 提供部分特例化
template<typename T>
class MyVector<T(*)(T, T)> {
public:
MyVector() { cout << "MyVector<T(*)(T, T)>" << endl; }
};
*/
/*
写法2
MyVector 元素是函数指针,返回类型是R1,两个参数类型分别是R2,R3 提供部分特例化
template<typename R1, typename R2, typename R3>
class MyVector< R1(*)(R2, R3) >
{
public:
MyVector() { cout << "MyVector<R1(*)(R2, R3)>" << endl; }
};
*/
MyVector<int(int, int)> v5; //元素是函数对象类型,使用默认的函数版本,也可以使用如下方式
/*
template<typename R1, typename R2, typename R3>
class MyVector<R1(R2, R3)>//针对函数类型,进行部分特例化,有一个返回值,有两个形参
{
public:
MyVector() { cout << "MyVector<R1(R2, R3)>" << endl; }
};
*/
//函数指针类型
typedef int (*PFUNCTION) (int, int);
PFUNCTION pf1 = sum;
pf1(12, 13);
//函数类型
typedef int PFUNCTION2 (int, int);
PFUNCTION2 * pf2 = ∑
(*pf2)(12, 13);
system("pause");
//有完全特例化能匹配就用完全特例化版本,有部分特例化版本就用部分特例化,再没有就用缺省模板
return 0;
}
//问题:这种写法可以,但是 typename T 这种方式 范围太大了!!优化如下
template<typename T>
void function(T _t) {
cout << typeid(T).name() << endl;
}
template<typename R, typename R1, typename R2>
//细分到可以取出返回值类型R1,形参1类型R2,形参2类型R3 还可以继续细分 如下
void function(R1(*)(R2,R3)) {
cout << typeid(R1).name() << endl;
cout << typeid(R2).name() << endl;
cout << typeid(R3).name() << endl;
}
//效果,继续细分到可以取出返回值类型R1,哪个类类型T,形参1类型R1,形参2类型R2 Good
template<typename R, typename T, typename R1, typename R2>
void function3(R1(T::*)(R2, R3)) {
cout << typeid(T).name() << endl;
cout << typeid(R1).name() << endl;
cout << typeid(R2).name() << endl;
cout << typeid(R3).name() << endl;
}
class Test {
public:
int sum(int x, int y) { return x + y; }
};
int main() {
function3(&Test::sum);
}
<五>模板的完全特例化和非完全特例化的更多相关文章
- Apache Sqoop 结构化、非结构化数据转换工具
简介: Apache Sqoop 是一种用于 Apache Hadoop 与关系型数据库之间结构化.非结构化数据转换的工具. 一.安装 MySQL.导入测试数据 1.文档链接:http://www.c ...
- c++11-17 模板核心知识(三)—— 非类型模板参数 Nontype Template Parameters
类模板的非类型模板参数 函数模板的非类型模板参数 限制 使用auto推断非类型模板参数 模板参数不一定非得是类型,它们还可以是普通的数值.我们仍然使用前面文章的Stack的例子. 类模板的非类型模板参 ...
- 特例模式(Special Case Pattern)与空对象模式(Null Pointer Pattern)—— 返回特例对象而非 null
返回 null 值,基本上是在给自己增加工作量,也是给调用者添乱.只有一处没有检查返回的是否为 null,程序就会抛 NullPointerException 异常. 如果你打算在方法中返回 null ...
- Hadoop基础-Apache Avro串行化的与反串行化
Hadoop基础-Apache Avro串行化的与反串行化 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Apache Avro简介 1>.Apache Avro的来源 ...
- JS 函数的柯里化与反柯里化
===================================== 函数的柯里化与反柯里化 ===================================== [这是一篇比较久之前的总 ...
- 浅谈html语义化标签,Html5新增语义化标签
Html语义化标签,Html5新增语义化标签 自己在学习的期间,整理了下html关于语义化标签的一些知识,列的不是很全. 希望大家有新的见解可以给我留言,我会补充上去,谢谢大家 1.什么是语义化标签? ...
- DevExpress 14.2 批量汉化 以及客户端的汉化
DXperience汉化方法介绍 运用慧都提供的DXperience汉化包,能将最新版本的DXperience WinForm和ASP.NET控件界面.弹出框.右键菜单等汉化成中文,且能根据自己的需求 ...
- JS的防抖,节流,柯里化和反柯里化
今天我们来搞一搞节流,防抖,柯里化和反柯里化吧,是不是一看这词就觉得哎哟wc,有点高大上啊.事实上,我们可以在不经意间用过他们但是你却不知道他们叫什么,没关系,相信看了今天的文章你会有一些收获的 节流 ...
- web标签语义化的理解_web语义化是什么意思
web语义化是什么? Web语义化,使用语义恰当的标签,可以让页面具有良好的结构,页面元素具有良好的含义,从而让人和机器都能快速理解.语义化的web页面一方面可以让机器在更少的人类干预情况下收集并研究 ...
- 玩转Django2.0---Django笔记建站基础五(模板)
第五章 模板 Django作为web框架,需要一种很便利的方法去动态地生成HTML网页,因此有了模板这个概念.模板包含所需HTML的部分代码以及一些特殊语法 Django可以配置一个或多个模板引擎(甚 ...
随机推荐
- 升级openssl和openssh脚本
#!/bin/bash # 原先的版本号信息 # openssl version #OpenSSL 1.0.2k-fips 26 Jan 2017 # ssh -V #OpenSSH_7.4p1, O ...
- 路径参数:Path Parameters
官方文档地址:https://fastapi.tiangolo.com/zh/tutorial/path-params/ # -*- coding: UTF-8 -*- from fastapi im ...
- 分步骤讲解Deployment故障排除
背景假设 当你希望在Kubernetes中部署应用程序时,你通常会定义三个组件: 一个Deployment - 这是一份用于创建你的应用程序的Pod副本的"食谱": 一个Servi ...
- 洛谷P2865 [USACO06NOV]Roadblocks G(次短路)
一个次短路的问题,可以套用dijkstra求最短路的方法,用dis[0][i]表示最短路:dis[1][i]表示次短路,优先队列中存有最短路和次短路,然后每次找到一条道路对他进行判断,更新最短或次短路 ...
- HDU1561 The more, The Better(树形背包)
通过这道题对树形背包理解更深一步...... 有几个地方需要注意: 1.本题数据结构为森林,需增加一个超根作为根节点,M+=1(后面解释). 2.本题有拓扑序的限制,通过vector建成的一棵树中,必 ...
- 《吐血整理》高级系列教程-吃透Fiddler抓包教程(28)-Fiddler如何抓取Android7.0以上的Https包-下篇
1.简介 虽然依旧能抓到大部分Android APP的HTTP/HTTPS包,但是别高兴的太早,有的APP为了防抓包,还做了很多操作:① 二次加密有的APP,在涉及到关键数据通信时,会将正文二次加密后 ...
- jmeter中获取token和cookie
## 登录获取token 1.添加请求 1.1 输入接口中需要携带的参数的值 2.正则表达式提取器提取出值 3.输入token数据 "token":"(.+?)" ...
- 归纳学习(Inductive Learning),直推学习(Transductive Learning),困难负样本(Hard Negative)
归纳学习(Inductive Learning): 顾名思义,就是从已有训练数据中归纳出模式来,应用于新的测试数据和任务.我们常用的机器学习模式就是归纳学习. 直推学习(Transductive Le ...
- Redis Cluster 原理说的头头是道,这些配置不懂就是纸上谈兵
Redis Cluster 原理说的头头是道,这些配置不懂就是纸上谈兵 Redis Cluster 集群相关配置,使用集群方式的你必须重视和知晓.别嘴上原理说的头头是道,而集群有哪些配置?如何配置让集 ...
- JavaScript进阶(Learning Records)
背景:对JavaScript的深入学习 参考:<JavaScript高级程序设计><冴羽 JavaScript 深入> 从原型到原型链 prototype prototype是 ...