59 - 类模板与函数模板的深度剖析

news2024/11/24 10:03:58

---- 整理自狄泰软件唐佐林老师课程

1. 多参数模板

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

在这里插入图片描述

2. 类模板可以被 特化

模板本来是一组通用逻辑的实现,但是可能存在特定的参数类型下,通用的逻辑实现不能满足要求,这时就需要针对这些特殊的类型,而实现一个特例模板——即 模板特化

  • 指定类模板的特定实现
  • 部分类型参数必须显示指定
  • 根据类型参数分开实现类模板

在这里插入图片描述

2.1 类模板的特化类型

  • 部分特化:用特定规则约束类型参数
  • 完全特化:完全显示指定类型参数
// 主模板类
template <typename T1, typename T2> 
class Test
{
};
// 完全特化
template < > 
class Test<int, int>
{
};
// 部分特化:对部分模板参数进行特化为一般类型
template <typename T2> 
class Test<int, T2>
{
};
// 部分特化:模板参数特化为指针
template <typename T1, typename T2> 
class Test<T1*, T2*>
{
};

2.2 编程实验:类模板的特化

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

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

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(1, 2.5);
    
    t2.add(5, 5);
    t2.print();
    
    t3.add(NULL, NULL);
    
    Test<int*, double*> t4;
    int a = 1;
    double b = 0.1;
    
    t4.add(&a, &b);
    
    return 0;
}

在这里插入图片描述

2.3 类模板特化注意事项

  • 特化只是模板的分开实现
    • 本质上是 同一个类模板
  • 特化类模板的使用方式是统一的
    • 必须 显示 指定每一个类型参数

3. 特化的深度分析

3.1 问题

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

3.2 重定义和特化的不同

  • 重定义
    • 一个类模板和一个新类(或者两个类模板)
    • 使用的时候需要 考虑如何选择的问题
  • 特化
    • 以统一的方式使用类模板和特化类
    • 编译器自动优先选择特化类

3.3 函数模板的特化

部分内容引用修改自:
https://blog.csdn.net/zhaominyong/article/details/109265862

3.3.1 函数模板只支持类型参数完全特化

在这里插入图片描述

// 常规函数
bool Equal(const char* left, const char* right)
{
}
// 函数主模板
template<typename T1, typename T2> 
bool Equal(T1 left, T2 right)
{
}
// 函数模板的完全特化
template< > 
bool Equal<void*>(void* left, void* right)
{
}
// 函数模板的重载(新的函数模板)
template<typename T1, typename T2> 
bool Equal(T1* left, T2* right)
{
}

3.3.2 函数模板之间的重载决议

#include <iostream>
using namespace std;

// 函数主模板
template<typename T1, typename T2>
void Equal(T1 left, T2 right)
{
    cout << "template<typename T1, typename T2> void Equal(T1 left, T2 right)" << endl;
}

// 函数模板的完全特化
template< >
void Equal(const char* left, const char* right)
{
    cout << "template< > void Equal<const char*>(const char* left, const char* right)" << endl;
}

// 函数模板的重载(新的函数模板)
template<typename T1, typename T2>
void Equal(T1* left, T2* right)
{
    cout << "template<typename T1, typename T2> void Equal(T1* left, T2* right)" << endl;
}

int main()
{
    Equal("1", "2");

    return 0;
}

在这里插入图片描述

#include <iostream>
using namespace std;

// 函数主模板
template<typename T1, typename T2>
void Equal(T1 left, T2 right)
{
    cout << "template<typename T1, typename T2> void Equal(T1 left, T2 right)" << endl;
}

// 函数模板的重载(新的函数模板)
template<typename T1, typename T2>
void Equal(T1* left, T2* right)
{
    cout << "template<typename T1, typename T2> void Equal(T1* left, T2* right)" << endl;
}

// 函数模板的完全特化
template< >
void Equal(const char* left, const char* right)
{
    cout << "template< > void Equal<const char*>(const char* left, const char* right)" << endl;
}

int main()
{
    Equal("1", "2");

    return 0;
}

在这里插入图片描述

3.3.3 普通函数与函数模板间的重载决议

#include <iostream>
using namespace std;

// 函数主模板
template<typename T1, typename T2>
void Equal(T1 left, T2 right)
{
    cout << "template<typename T1, typename T2> void Equal(T1 left, T2 right)" << endl;
}

// 函数模板的完全特化
template< >
void Equal(const char* left, const char* right)
{
    cout << "template< > void Equal<const char*>(const char* left, const char* right)" << endl;
}

// 函数模板的重载(新的函数模板)
template<typename T1, typename T2>
void Equal(T1* left, T2* right)
{
    cout << "template<typename T1, typename T2> void Equal(T1* left, T2* right)" << endl;
}

// 普通函数
void Equal(const char* left, const char* right)
{
    cout << "void Equal(const char* left, const char* right)" << endl;
}

int main()
{
    Equal("1", "2");

    return 0;
}

在这里插入图片描述

3.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
<  >
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()
{  
    cout << Equal( 1, 1 ) << endl;
    cout << Equal<>( 0.001, 0.001 ) << endl;
    
    return 0;
}

在这里插入图片描述
在这里插入图片描述

3.5 工程中的建议

  • 当需要重载函数模板时,优先考虑使用模板特化
  • 当模板特化无法满足需求时,再使用函数重载(如上例)

4. 小结

  • 类模板可以定义任意多个不同的类型参数
  • 类模板可以被部分特化和完全特化
  • 特化的本质是模板的分开实现
  • 函数模板只支持完全特化
  • 工程中使用模板特化代替类(函数)重定义

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/45878.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【密码学基础】RSA加密算法

1 RSA介绍 RSA是一种非对称加密算法&#xff0c;即加密和解密时用到的密钥不同。加密密钥是公钥&#xff0c;可以公开&#xff1b;解密密钥是私钥&#xff0c;必须保密保存。基于一个简单的数论事实&#xff1a;两个大质数相乘很容易&#xff0c;但想要对其乘积进行因式分解却…

IIS 部署 SSL 证书提示证书链中的一个或多个中间证书丢失

现象描述 IIS Web 服务部署免费 SSL 证书时提示 “证书链中的一个或多个中间证书丢失&#xff0c;要解决此问题&#xff0c;请确保安装了所有中间证书”。 下载中间证书文件&#xff0c;根据您的证书加密算法类型下载中间证书至您的云服务器中。 安装中间证书 1. 在您需要部…

Arcgis地理配准栅格数据

前提 有时候获取的不同数据没有坐标,而却有共同点,这时候需要对数据进行配准校正,数据才能最终拼接镶嵌在一起 效果 1、准备数据 2、打开地理配准工具 3、地理配准中设置待配准数据 4、添加控制点 这份数据目测很容易找到控制点 在待配准数据上先选择控制点,再在基准数…

JavaScript_BOM

JavaScript_BOM BOM&#xff1a;Browser Object Model 浏览器对象模型。也就是 JavaScript 将浏览器的各个组成部分封装为对象。 我们要操作浏览器的各个组成部分就可以通过操作 BOM 中的对象来实现。 BOM 中包含了如下对象&#xff1a; Window&#xff1a;浏览器窗口对象N…

JavaScript基础语法(类型转换)

JavaScript基础语法&#xff08;类型转换&#xff09; 使用运算符的时候会发生类型转换。 其他类型转为number string转换为 number类型&#xff1a;按照字符串的字面值&#xff0c;转为数字。如果字面值不是数字&#xff0c;则转为NaN 将 string转换为 number有两种方式&…

存储器管理

文章目录存储器的层次结构存储器的指标多层结构的存储器系统主存储器与寄存器高速缓存和磁盘缓存程序的装入和链接对用户程序的处理步骤程序的装入程序的链接连续分配的存储管理方式单一连续分配固定分区分配动态分区分配基于顺序搜索的动态分区分配算法基于索引搜索的动态分区…

EventLoop

1.javascript是一门单线程语言 任务1 ---> 任务2--->任务3 单线程执行任务队列的问题&#xff1a; 如果前一个任务非常耗时&#xff0c;则后面的任务不得不一直等待&#xff0c;从而导致程序假死问题 2.同步任务和异步任务 同步任务&#xff1a;js主线程直接执行 同…

沉睡者IT - 什么是Web3.0?

欢迎关注沉睡者IT&#xff0c;点上面关注我 ↑ ↑ 什么是Web3.0&#xff1f; Web3&#xff08;也称为Web 3&#xff09;用最简单的话来解释就是&#xff0c;第三代互联网。 那么有朋友要问了&#xff0c;那么什么是第一代&#xff0c;什么是第二代&#xff1f;第三代又有什么…

2.1 Redis中SDS的定义

每个sds.h/sdshdr 结构表示一个SDS值 struct sdshdr { //记录 buf 数组中已经使用的字节数量 //等于SDS所保存字符串的长度 int len;//记录buf数组中未使用字节的数量 int free;//字节数组,用于保存字符串 char buf[]; };图2-1 展示了一个SDS 示例: 1、free 属性值为0&#x…

Kotlin 开发Android app(十三):RadioGroup和ViewPager控件实现底层分页按钮

安卓的控件是挺多的&#xff0c;没有办法一个一个的来说明&#xff0c;我们挑出了一些重点的控件&#xff0c;组成一些常见的布局&#xff0c;这样以后在遇到相同功能的界面时&#xff0c;就会有自己的思路&#xff0c;或者进行复用。 在这一节中&#xff0c;我们实现一个底层分…

CANoe-vTESTstudio之State Diagram编辑器(元素介绍)

State Diagram编辑器里的工具箱,有多个图形符号,它们是组成状态图表的图形元素,具有不同的作用。图形元素能够高效并快速地创建状态图表,然后生成测试用例 1. 基本测试设计元素 1.1 Setup Setup元素的测试代码能够执行一次,在检查测试用例之前。例如,用于建立诊断连接 …

uni-app接入mPaas扫码

目录 原因 配置mPaas应用 包名和打签名APK 使用云端插件 打自定义基座 原因 可以用uni.scanCode扫一下下面的二维码&#xff0c;会发现&#xff0c;左边的识别不了&#xff0c;而右边的能识别&#xff0c;其实人眼看&#xff0c;两个二维码应该是一样的。 只不过左边的会有…

String的几个面试题

1.. 第一个只出现一次的字符 class Solution {public int firstUniqChar(String s) {int []count new int[125];for(int i0;i<s.length();i){char chs.charAt(i);count[ch];}for(int i0;i<s.length();i) {char ch s.charAt(i);if (count[ch] 1) {return i;}}return -1…

网站被DDOS攻击怎么办?防护经验!

为了能够及时发现ddos攻击&#xff0c;下面我们就详细介绍一下网站受ddos攻击的症状&#xff1a; 网站遇到ddos攻击的表现之一&#xff1a;服务器CPU被大量占用 ddos攻击其实是一种恶意性的资源占用攻击&#xff0c;攻击者利用肉鸡或者攻击软件对目标服务器发送大量的无效请求&…

详解设计模式:代理模式

代理模式&#xff08;Proxy Pattern&#xff09;&#xff0c;Java 常见的设计模式之一&#xff0c;是 GoF 的 23 种设计模式中的一种结构型设计模式。 代理模式 是指客户端并不直接调用实际的对象&#xff0c;而是通过调用代理对象&#xff0c;来间接的调用实际的对象。代理对象…

矢量三维电磁铁的技术参数

产品介绍&#xff1a; 锦正茂自主研发的多极电磁铁以四极电磁铁居多&#xff0c;也有五极、六极、八极等多极的应用&#xff0c;主要应用于多极磁环充磁、径向梯度磁场、旋转磁场磁导向等多种应用。 产品用途&#xff1a; 电磁铁/电磁场发生器主要用于磁滞现象研究、磁化系数测…

SAP-S4 BP 业务伙伴(客户与供应商)管理后台配置

目录 一、定义业务伙伴角色 二、客户和BP主数据同步配置 三 、激活对话中平台对象的PPo请求 四、勾选活动的同步选项 五、定义编码范围 ​编辑 六、 设置客户与供应商的编码范围 一、定义业务伙伴角色 业务伙伴 IMG路径 &#xff1a; 跨应用组件->SAP业务伙伴 -> …

热门Java开发工具IDEA入门指南——如何配置IDE

IntelliJ IDEA&#xff0c;是java编程语言开发的集成环境。IntelliJ在业界被公认为最好的java开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能是非常强大的。 上文…

HarmonyOS应用API手势方法-PinchGesture

描述&#xff1a;用于触发捏合手势&#xff0c;触发捏合手势的最少手指为2指&#xff0c;最大为5指&#xff0c;最小识别距离为3vp。 Api&#xff1a;从API Version 7开始支持 接口&#xff1a;PinchGesture(value?: { fingers?: number, distance?: number }) 参数&…

【Android App】实战项目之仿微信的私信和群聊App(附源码和演示视频 超详细必看)

需要全部代码请点赞关注收藏后评论区留言私信~~~ 手机最开始用于通话&#xff0c;后来增加了短信功能&#xff0c;初步满足了人与人之间的沟通需求。然而短信只能发文字&#xff0c;于是出现了能够发图片的彩信&#xff0c;但不管短信还是彩信&#xff0c;资费都太贵了&#xf…