【C++】详解C++的模板

news2024/12/28 4:10:55

目录

概念

​编辑

 语法

函数模板

类模板

 非类型模板参数

模板的特化

函数模板特化

类模板特化

全特化

偏特化

分离编译


概念

模板是C++中非常厉害的设计,模板把通用的逻辑剥离出来,让不同的数据类型可以复用同一种模板的逻辑,甚至可以让不同的逻辑复用同一种模板逻辑(仿函数的设计)

【C++】详解STL的适配器容器之一:优先级队列 priority_queue-CSDN博客

模板可以帮助我们实现代码的重用和泛化,提高代码的灵活性和可维护性。

STL的容器就是对模板很好的运用,可参考

【C++】详解STL容器之一的 vector-CSDN博客

【C++】详解STL的容器之一:list-CSDN博客

 语法

template <typename T> //可以写成template <class T> 
class MyClass {
    // ...
};

template <typename T> //可以写成template <class T> 
T add(T a, T b) {
    return a + b;
}

在上面的示例中,MyClass 是一个类模板,add 是一个函数模板。通过使用 typename class 关键字声明模板参数T 就是未知类型

函数模板

通过使用函数模板,我们可以定义一种通用的函数,可以根据实际需要传不同的数据复用函数模板

函数模板的语法格式如下

template <typename T>
返回类型 函数名(参数列表) {
    // 函数体
}

其中,template关键字表示这是一个函数模板,<typename T>表示定义了一个类型参数T,可以根据需要使用不同的类型来替换T返回类型表示函数的返回类型,函数名表示函数的名称,参数列表表示函数的参数列表。

在函数模板中,可以使用类型参数T作为函数的参数类型、返回类型或局部变量的类型。例如:

template <typename T>
T max(T a, T b) {
    return (a > b) ? a : b;
}

上述代码定义了一个函数模板max,它接受两个参数a和b,这两个参数的类型都是T,并且返回类型也是T

使用函数模板时,需要在函数名后面加上尖括号<>,并在其中指定具体的类型。例如:

int result1 = max<int>(3, 5); // 使用int类型实例化函数模板
double result2 = max<double>(3.14, 2.71); // 使用double类型实例化函数模板

max<int>表示使用`int`类型实例化max函数模板,max<double>表示使用double类型实例化max函数模板。传不同的参数示例化的函数是不同的

函数模板还可以有多个类型参数,可以使用逗号分隔它们。例如:

template <typename T1, typename T2>
void printPair(T1 a, T2 b) {
    cout << "(" << a << ", " << b << ")" << endl;
}

使用函数模板时,需要指定每个类型参数的具体类型。例如:

printPair<int, double>(3, 3.14); // 使用int和double类型实例化函数模板

在上述代码中,printPair<int, double>表示使用int类型和double类型实例化printPair函数模板。

总结起来,函数模板是一种通用的函数定义,可以用于多种不同类型的参数。通过使用函数模板,可以编写一次代码,然后在不同的地方使用不同的数据类型进行调用。

类模板

通过使用类模板,我们可以定义一种通用的类模板,可以根据实际需要在不同场景下传入不同的类型实例化出不同的类。

类模板的语法格式如下:

template <typename T> //可以写成template <class T>
class 类名 {
    // 成员变量和成员函数的定义
};

在类模板中,可以使用类型参数T作为成员变量的类型、成员函数的参数类型或返回类型。例如:

template <typename T>
class Stack {
private:
    T* data;
    int size;
public:
    Stack(int capacity) {
        data = new T[capacity];
        size = 0;
    }
    
    void push(T value) {
        data[size++] = value;
    }
    
    T pop() {
        return data[--size];
    }
};

上述代码定义了一个类模板Stack,它有一个私有成员变量data和size,分别表示存储数据的数组和当前栈的大小。类模板还有两个公有成员函数push和pop,分别用于向栈中压入元素和弹出栈顶元素。

使用类模板时,需要在类名后面加上尖括号<>,并在其中指定具体的类型。例如:

Stack<int> intStack(10); // 使用int类型实例化类模板
Stack<double> doubleStack(5); // 使用double类型实例化类模板

不然会报如下错误

Stack<int>表示使用int类型实例化Stack类模板,Stack<double>表示使用double类型实例化Stack类模板。根据实际的类型参数,编译器会生成相应的类定义。

类模板还可以有多个类型参数,可以使用逗号分隔它们。例如:

template <typename T1, typename T2>
class Pair {
private:
    T1 first;
    T2 second;
public:
    Pair(T1 a, T2 b) {
        first = a;
        second = b;
    }
    
    void print() {
        cout << "(" << first << ", " << second << ")" << endl;
    }
};

使用类模板时,需要指定每个类型参数的具体类型。例如:

Pair<int, double> p1(3, 3.14); // 使用int和double类型实例化类模板
Pair<string, int> p2("Hello", 5); // 使用string和int类型实例化类模板

 非类型模板参数

模板参数分为:类型形参非类型形参
类型形参:出现在模板参数列表中,跟在class或者typename之类的参数类型名称
非类型形参:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用
// 定义一个模板类型的静态数组
 template<class T, size_t N = 10>
 class array
 {
 public:
 T& operator[](size_t index){return _array[index];}
 const T& operator[](size_t index)const{return _array[index];}
 
 size_t size()const{return _size;}
 bool empty()const{return 0 == _size;}
 
 private:
 T _array[N];
 size_t _size;
 };
浮点数、类对象以及字符串是不允许作为非类型模板参数的
非类型的模板参数必须在编译期就能确认结果

模板的特化

概念:

在原模板类的基础上,针对特殊类型所进行特殊化的实现方式。模板特 化中分为函数模板特化与类模板特化

函数模板特化

必须要先有一个基础的函数模板
关键字 template 后面接一对空的尖括号 <>
函数名后跟一对尖括号,尖括号中指定需要特化的类型
函数形参表 必须要和模板函数的基础参数类型完全相同
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
 return left < right;
}
// 对Less函数模板进行特化
template<>
bool Less<Date*>(Date* left, Date* right) //Date是日期类
{
 return *left < *right;
}

下面是测试

关于日期类小编也写了一篇文章:【C++】如何用C++写一个日期计算器-CSDN博客

类模板特化

全特化

全特化即是将模板参数列表中所有的参数都确定化
template<class T1, class T2>
class Data
{
public:
 Data() {cout<<"Data<T1, T2>" <<endl;}
private:
 T1 _d1;
 T2 _d2;
};
template<>
class Data<int, char>
{
public:
 Data() {cout<<"Data<int, char>" <<endl;}
private:
 int _d1;
 char _d2;
};

下面是测试

偏特化

任何针对模版参数进一步进行条件限制设计的特化版本
偏特化有以下两种表现方式:
部分特化    
特化一部分参数
下面是测试代码
template<class T1, class T2>
class Data
{
public:
 Data() {cout<<"Data<T1, T2>" <<endl;}
private:
 T1 _d1;
 T2 _d2;
};
template <class T1>
class Data<T1, int>
{
public:
 Data() {cout<<"Data<T1, int>" <<endl;}
private:
 T1 _d1;
 int _d2;
};
限制参数
偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本
下面是测试代码
template<class T1, class T2>
class Data
{
public:
 Data() {cout<<"Data<T1, T2>" <<endl;}
private:
 T1 _d1;
 T2 _d2;
};
//两个参数偏特化为指针类型
template <typename T1, typename T2>
class Data <T1*, T2*>
{ 
public:
 Data() {cout<<"Data<T1*, T2*>" <<endl;}
 
private:
T1 _d1;
 T2 _d2;
};
//两个参数偏特化为引用类型
template <typename T1, typename T2>
class Data <T1&, T2&>
{
public:
 Data(const T1& d1, const T2& d2)
 : _d1(d1)
 , _d2(d2)
 {
 cout<<"Data<T1&, T2&>" <<endl;
 }
 
private:
 const T1 & _d1;
 const T2 & _d2; 
 };

分离编译

下面了解即可

C/C++程序要运行要经历以下步骤

预处理---> 编译---> 汇编---> 链接

预处理:将头文件展开

编译:头文件不参与编译,编译主要是检查语法错误,多个源文件单独分开编译

汇编:将文本文件翻译成二进制文件

链接:将多个编译好的源文件合成一个

如果将模板声明和定义分离会报链接错误

可参考下面这位大佬的文章

为什么C++编译器不能支持对模板的分离式编译-CSDN博客

 将声明和定义放到一个文件 "xxx.hpp" 里面或者xxx.h其实也是可以的。推荐使用这种
 模板定义的位置显式实例化。这种方法不实用,不推荐使用

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

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

相关文章

【智能优化算法】雁群优化算法(Wild Geese Algorithm,WGA)

雁群优化算法(Wild Geese Algorithm,WGA)是期刊“Array”的2021年智能优化算法 01.引言 雁群优化算法(Wild Geese Algorithm,WGA)用于大规模全局优化&#xff0c;并利用IEEE CEC 2008和CEC 2010高维D100、500、1000特别会议的大规模测试函数验证了该算法的效率和性能。WGA的灵…

Python专题:四、字符串(2)

字符串可以用 &#xff08;单引号&#xff09;和" "&#xff08;双引号&#xff09; 变量 字符串 len()计算字符串长度 可以通过下标&#xff0c; 字符串[]引用字符&#xff0c;不能超过下标数量&#xff0c;否则就会报错。 还可以用负数进行下标&#xff0c;表示…

【正点原子Linux连载】 第四十二章 多点电容触摸屏实验摘自【正点原子】ATK-DLRK3568嵌入式Linux驱动开发指南

1&#xff09;实验平台&#xff1a;正点原子ATK-DLRK3568开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id731866264428 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/docs/boards/xiaoxitongban 第四十…

C++复习 -- 常用关键字

this 关键字: 概念 在 C 中&#xff0c; this 关键字是一个指向调用对象的指针。它在成员函数内部使用&#xff0c;用于引用调用该函数的对象。使用 this 可以明确指出成员函数正在操作的是哪个对象的数据成员。 case :证明他就是一个指向被调用对象的指针: #include <iost…

Nginx的正向代理与反向代理

你好呀&#xff0c;我是赵兴晨&#xff0c;文科程序员。 今天&#xff0c;我们将一起了解什么是Nginx的正向代理&#xff1f;什么是Nginx的反向代理&#xff1f;并实际动手实践。 以下内容都是满满的干货&#xff0c;绝对不容错过。我建议先收藏这篇文章&#xff0c;然后找一…

Transformer+Classification学习笔记

论文名称&#xff1a;An Image is Worth 16x16 Words:Transformers for Image Recognition at Scale [2112.11010] MPViT: Multi-Path Vision Transformer for Dense Prediction (arxiv.org) 参考博客与视频&#xff1a; Vision Transformer 超详细解读 (原理分析代码解读) …

Jmeter 性能-需求分析业务/场景设计

1、性能测试需求分析与业务调研 性能测试的需求不能直接从产品经理那里获得&#xff0c;因为产品经理定义的性能需求比较抽象。 要落实到可执行的性能测试需求往往需要进一步分析和细化。这也是为什么获取具体的性能需求比较难的一个原因。 一般情况下&#xff0c;要知道性能…

(二刷)代码随想录第6天|242.有效的字母异位词、349.两个数组的交集

242.有效的字母异位词 242. 有效的字母异位词 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 学透哈希表&#xff0c;数组使用有技巧&#xff01;Leetcode&#xff1a;242.有效的字母异位词_哔哩哔哩_bilibili 给定两个字符串 s 和 t &#xff…

基于大模型训练的数字识别

创作原因 现在写电赛题&#xff0c;题目有识别数字的要求。但使用设备openmv使用模板匹配的算法帧率很低&#xff0c;且识别效果不是很好&#xff0c;于是我们就想到了利用神经网络训练模型来识别数字 正文部分 内容介绍 本文内容是基于openmv使用Edge Impulse训练大模型。…

网络安全等级保护测评指标解读(2.0)

网络安全等级保护2.0测评指标解读&#xff1a; 1、物理和环境安全 2、网络和通信安全 3、设备和计算安全 4、应用和数据安全 5、安全策略和管理制度 6、安全管理机构和人员 7、安全建设管理 8、安全运维管理 软件资料清单列表部分文档&#xff1a; 工作安排任务书&#xff0c;…

【数据结构】红黑树(定义性质、插入、查找、删除)解析+完整代码

3.3 红黑树 3.3.1 定义和性质 为什么发明红黑树&#xff1f; 平衡二叉树和红黑树的时间复杂度相同&#xff0c;但是平衡二叉树的平衡特性容易被破坏&#xff0c;需要频繁调整树的形态。 红黑树RBT&#xff1a;插入/删除很多时候不会破坏红黑特性&#xff0c;无需频繁调整树的形…

Kimi智能助手:你的全天候AI伙伴

Kimi使用链接&#xff1a; https://kimi.moonshot.cn/ Kimi手机端下载链接&#xff1a; https://kimi.moonshot.cn/download/app?refchat 简介&#xff1a; Kimi AI 是由月之暗面科技有限公司&#xff08;Moonshot AI&#xff09;开发的一款人工智能助手&#xff0c;它具备多…

正运动技术与合作伙伴邀您共聚2024武汉光博会

■展会名称&#xff1a; 2024“中国光谷”光电子博览会暨论坛&#xff08;以下简称“武汉光博会”&#xff09; ■展会日期 2024年5月16日 - 18日 ■展馆地点 中国光谷科技会展中心A3馆 ■展位号 3A21 5月16至18日&#xff0c;中国光谷科技会展中心将举办第二十届武汉光…

nmap使用教程

nmap使用教程 一、nmap简介二、nmap常用命令2.1、target specification&#xff08;目标规范&#xff09;2.1.1、用法2.1.2、详情 2.2、HOST DISCOVERY&#xff08;主机发现&#xff09;2.2.1、用法2.2.2、详情 2.3、SCAN TECHNIQUES&#xff08;扫描技术&#xff09;2.4、PORT…

【Web】HNCTF 2024 题解(部分)

目录 Please_RCE_Me ezFlask GoJava ez_tp GPTS Please_RCE_Me <?php if($_GET[moran] flag){highlight_file(__FILE__);if(isset($_POST[task])&&isset($_POST[flag])){$str1 $_POST[task];$str2 $_POST[flag];if(preg_match(/system|eval|assert|call|…

从零开始开发企业培训APP:在线教育系统源码剖析

今天&#xff0c;小编将深入剖析企业培训APP的开发&#xff0c;从零开始为企业构建一个高效、实用的在线教育系统。 一、需求分析 1.主要功能需求 包括但不限于&#xff1a; -用户管理 -课程管理 -学习计划 -互动功能 -考核评估 -统计分析 二、技术选型 1.前端技术 …

PG数据文件和块管理与Oracle比较

之前有说过PG数据库中的对象oid与数据文件一一对应&#xff0c;创建的数据库如果没有指定表空间&#xff0c;则会默认放在默认表空间中&#xff0c;例如&#xff1a; 1.对象OID与数据文件对应关系 Oracle的逻辑与物理对应关系如下&#xff1a; 两种结果相比较而言&#xff1a; …

拯救者杯OPENAIGC开发者大赛城市巡回沙龙,苏州站报名开启!

由联想拯救者、AIGC开放社区、英特尔联合主办的“AI生成未来第二届拯救者杯OPENAIGC开发者大赛”自上线以来&#xff0c;吸引了广大开发者的热情参与。 为了向技术开发者、业务人员、高校学生、以及个体创业人员等参赛者们提供更充分的帮助与支持&#xff0c;AIGC开放社区特别…

RockChip Android8.1 EthernetService分析

一:概述 本篇文章将围绕RK Android8.1 SDK对Ethernet做一次框架分析,包含Framework层和APP层。 当前版本SDK默认只支持一路Ethernet,熟悉Ethernet工作流程后通过修改最终会在系统Setting以太网中呈现多路选项(可以有多种实现方式),博主通过增加ListPreference实现的效果…

C++设计模式|创建型 5.原型模式

1.什么是原型模式&#xff1f; 原型模式⼀种创建型设计模式&#xff0c;该模式的核⼼思想是基于现有的对象创建新的对象&#xff0c;⽽不是从头开始创建。 在原型模式中&#xff0c;通常有⼀个原型对象&#xff0c;它被⽤作创建新对象的模板。新对象通过复制原型对象的属性和状…