C++模板编程

模板是泛型编程的基础,先给出泛型编程的概念。

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。

应用场景:比如要实现一个通用的,进行两个变量互相交换的函数,此时可以通过函数重载的方式,用不同的参数类型来实现该函数。但是是有缺陷的,因此也引出了模板编程。

1. 函数重载只是参数类型不同,当出现新类型的参数时,就要手动的再实现一份。

2. 代码的可维护性较低,一个出错可能导致所有的同名函数都出现问题。

模板是一个模具,通过用户传入的参数类型来生成对应类型的具体代码。本质是将重复的工作交给了编译器完成。

模板分为函数模板类模板

函数模板

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

template<typename T1, typename T2, ...., typename Tn>(此处的typename也可写作class)

返回值类型 函数名(参数列表){}

函数模板是一个蓝图,它本身并不是函数,是编译器用使用特定方式产生具体类型函数的模具。

具体例子:

template<class T>
void Swap(T& num1, T& num2)
{
	std::swap(num1, num2);
}
template<typename T1, typename T2>
void PrintType(T1& val1, T2& val2)
{
	std::cout << typeid(val1).name() << std::endl;
	std::cout << typeid(val2).name() << std::endl;
}
int main()
{
	int a = 10, b = 20;
	Swap(a, b);
	std::cout << a << " " << b << std::endl;//20 10
	double c = 1.0;
	PrintType(a, c);//int, double
	return 0;
}

函数模板原理

编译器编译阶段,编译器根据传入的实参类型来推演生成对应类型的函数以供调用。例如:当用int类型使用函数模板时,编译器通过对实参类型的推演,将T确定为int类型,然后产生一份专门处理int类型的代码。

函数模板实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。

函数模板的实例化又分为隐式实例化和显式实例化

隐式实例化

让编译器根据传入的参数类型自动进行参数类型的推演。

显式实例化

在函数名后的< >中指定模板参数的实际类型

例如vector<int> array;

模板参数匹配规则

(1)一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

(2)对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模 板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。

(3)模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。

类模板

类模板定义格式

template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
//例子
template<class T>
class Base
{
public:
private:
    T _num;
};

类模板实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的 类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

非类型模板参数

     模板参数分为类型形参与非类型形参。 类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。 非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

具体例子:

template<class T, size_t N = 10>
class Base
{
private:
	T _array[N];
};

注意: 1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的。

            2. 非类型的模板参数必须在编译期就能确认结果。

模板特化

通常情况下,模板的使用可以实现与类型无关的代码,但有些特殊类型会得出错误的结果,此时需要对特殊类型进行特殊处理,称为模板特化。

函数模板的特化

具体例子:

class Base
{
public:
	int _left;
	int _right;
};
template<class T>
bool IsSame(T left, T right)
{
	return left == right;
}
template<>
bool IsSame<Base*>(Base* left, Base* right)//模板特化,对Base* 类型进行特殊处理
{
	return left->_left == right->_left && left->_right == right->_right;
}

函数模板的特化步骤:

1. 必须要先有一个基础的函数模板。

2. 关键字template后面接一对空的尖括号<>。

3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型。

4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。

类模板特化

类模板特化又分为全特化和偏特化

全特化就是将模板中的参数全都确定化。


template<class T1, class T2>
class Base
{
public:
	T1 _left;
	T2 _right;
};
template<>
class Base<char, int>
{
public:
	char _left;
	int _right;
};

偏特化:任何针对模版参数进一步进行条件限制设计的特化版本。

偏特化有两种表现形式,部分特化和进一步对参数进行限制

具体例子:


template<class T1, class T2>
class Base
{
public:
	T1 _left;
	T2 _right;
};
//部分特化
template<class T1>
class Base<T1, int>
{
public:
	T1 _left;
	int _right;
};
//对参数进行进一步限制
template<typename T1, typename T2>
class Base <T1*, T2*>//指针类型
{ 
public:
    T1 _d1;
    T2 _d2;
};

模板分离编译

分离编译:一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。

模板是不支持声明和定义分离的。

原因:

C/C++程序要运行,是要经过 预编译->编译->汇编->链接 四个步骤的,其中预编译主要是进行文本处理,即宏替换,头文件的包含,以及注释的删除等;编译则是会对代码根据语言特性进行词法、语法、语义的分析,并形成汇编代码,同时对符号进行整合;汇编则是在此基础上,将汇编代码进一步翻译成二进制,同时形成符号表,链接时会将对应符号的地址填到符号表中,处理没有解决的地址问题。

而因为模板的声明和定义分离之后,编译器在编译时,会默认该模板函数的地址已经确定,所以只会在最后链接阶段,寻找相应模板函数的地址进行填表,但由于模板没有实例化,所以地址并不存在,所以链接阶段就会因为找不到对应的函数地址而报错。

解决方法:

建议将模板的声明和定义统一放到一个文件中,例如.hpp文件。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu配置VScode的C++环境

在Ubuntu系统下配置C环境&#xff0c;并运行helloworld 1. 下载VScode 我这里使用的是星火应用商店&#xff0c;在商店里面可以直接下载安装 http://spark-app.store/ 2.创建文件夹 3.启动VScode并打开该文件夹 4.安装以下几个扩展 PS&#xff1a;Clang这个插件别安装&…

3. DAX 时间函数-- DATE 日期--一生二,二生三,三生万物

在数据分析过程中&#xff0c;经常需要从一个数据推到另外一个数据&#xff0c;日期数据也是如此&#xff0c;需要从一个日期推到另外一个相关的日期&#xff0c;或者从一群日期推到另外一个相关的日期/一群相关的日期。这一期说的就是日期之间彼此推衍的函数&#xff0c;会比之…

C# 操作PDF表单 - 创建、填写、删除PDF表单域

通常情况下&#xff0c;PDF文件是不可编辑的&#xff0c;但PDF表单提供了一些可编辑区域&#xff0c;允许用户填写和提交信息。PDF表单通常用于收集信息、反馈或进行在线申请&#xff0c;是许多行业中数据收集和交换的重要工具。 PDF表单可以包含各种类型的输入控件&#xff0…

QT:事件机制

作业&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimerEvent> #include <QTime> #include<QPushButton> #include <QTextToSpeech>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAME…

头歌-机器学习 第15次实验 朴素贝叶斯分类器

第1关:条件概率 任务描述 本关任务:根据本节课所学知识完成本关所设置的选择题。 相关知识 为了完成本关任务,你需要掌握条件概率。 条件概率 朴素贝叶斯分类算法是基于贝叶斯定理与特征条件独立假设的分类方法,因此想要了解朴素贝叶斯分类算法背后的算法原理,就不得…

【CSS】一篇文章讲清楚screen、window和html元素的位置:top、left、width、height

一个Web网页从内到外的顺序是&#xff1a; 元素div,ul,table... → 页面body → 浏览器window → 屏幕screen 分类详情屏幕screen srceen.width - 屏幕的宽度 screen.height - 屏幕的高度&#xff08;屏幕未缩放时&#xff0c;表示屏幕分辨率&#xff09; screen.availLeft …

(一)基于IDEA的JAVA基础13

数组遍历 遍历数组就是把数组内的数据一个个的取出来 1.我们可以用for循环&#xff0c;依次把数字类的元素取出来。 2.增强型for循环。 用第一个方法写一下&#xff0c;看一下 public class Test01 { public static void main(String[] args) { //存储一组数据{…

TQ15EG开发板教程:在MPSOC上运行ADRV9009

首先需要在github上下载两个文件&#xff0c;本例程用到的文件以及最终文件我都会放在网盘里面&#xff0c; 地址放在最后面。在github搜索hdl选择第一个&#xff0c;如下图所示 GitHub网址&#xff1a;https://github.com/analogdevicesinc/hdl/releases 点击releases选择版…

【C++题解】1005 - 已知一个圆的半径,求解该圆的面积和周长

问题&#xff1a;1005 - 已知一个圆的半径&#xff0c;求解该圆的面积和周长 类型&#xff1a;基础问题、小数运算 题目描述&#xff1a; 已知一个圆的半径&#xff0c;求解该圆的面积和周长。 输入&#xff1a; 输入只有一行&#xff0c;只有 1 个整数。 输出&#xff1a…

迭代器模式【行为模式C++】

1.简介 迭代器模式是一种行为设计模式&#xff0c; 让你能在不暴露集合&#xff08;聚合对象&#xff09;底层表现形式 &#xff08;列表、 栈和树等&#xff09; 的情况下遍历集合&#xff08;聚合对象&#xff09;中所有的元素。 迭代器的意义就是将这个行为抽离封装起来&a…

【大厂生产案例】JVM调优

写作目的 最近上线了一个需求&#xff0c;遇到了一个JVM报警的问题&#xff0c;很荣幸能遇到&#xff0c;在此分享一下整个调优的过程。 背景 我们是中台服务&#xff0c;我们的甲方就是上游不同的业务。中台原则上是业务和能力分离&#xff0c;但是不可避免的是分不开&…

数据结构学习之路--全面破解顺序表的奥秘(附C源码)

好久不见啊~大家&#xff0c;今天为大家带来的主题是&#xff1a;顺序表的实现。 目录 前言 一、线性表的定义 二、线性表的顺序结构 1 顺序表的定义 2 顺序表的基本操作 2.1 初始化函数 2.2 顺序表的销毁 2.3 顺序表的扩容 2.4 顺序表的尾插 2.5 顺序表的尾删 …

【学习】软件测试需求分析要从哪些方面入手

软件测试需求分析是软件测试过程中非常重要的一个环节&#xff0c;它是为了明确软件测试的目标、范围、资源和时间等要素&#xff0c;以确保软件测试的有效性和全面性。本文将从以下几个方面对软件测试需求分析进行详细的阐述&#xff1a; 一、软件测试目标 软件测试目标是指…

LeetCode_145(二叉树的后序遍历)

1.递归 public List<Integer> postorderTraversal(TreeNode root) {List<Integer> res new ArrayList<>();accessTree(root,res);return res;}public void accessTree(TreeNode root, List<Integer> res){if(root null){return;}accessTree(root.le…

219 基于matlab的汽车悬架(钢板弹簧,减震器)设计程序GUI

基于matlab的汽车悬架&#xff08;钢板弹簧&#xff0c;减震器&#xff09;设计程序&#xff27;&#xff35;&#xff29;。根据需求输入设计参数&#xff0c;包括前桥负荷、簧下质量、弹簧刚度、阻尼等&#xff0c;输出钢板弹簧、减震器结果。程序已调通&#xff0c;可直接运…

FHE全同态加密简介

1. 何为FHE&#xff1f; FHE (Fully homomorphic encryption)&#xff1a; 是一种隐私技术&#xff0c;支持直接对密文进行计算&#xff0c;而无需对密文先解密再计算。即&#xff0c;任何第三方或云厂商&#xff0c;都可对敏感信息的密文进行处理&#xff0c;而无需访问密文内…

基于web的音乐网站的设计与实现(论文+源码)_kaic

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了音乐网站的开发全过程。通过分析音乐网站管理的不足&#xff0c;创建了一个计算机管理音乐网站的方案。文章介绍了音乐网站的系统分析部分&#xff0c;包括可行性…

最新ChatGPT4.0工具使用教程:GPTs使用,Midjourney绘画,AI换脸,Suno-AI音乐生成大模型一站式系统使用教程

一、前言 ChatGPT3.5、GPT4.0、相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和用户进行创作交流。 然而&#xff0c;GPT-4对普通用户来说都是需要额外付费才可以…

FPGA开源项目分享——基于 DE1-SOC 的 String Art 实现

导语 今天继续康奈尔大学FPGA课程ECE 5760的典型案例分享——基于DE1-SOC的String Art实现。 &#xff08;更多其他案例请参考网站&#xff1a; Final Projects ECE 5760&#xff09; 1. 项目概述 项目网址 ECE 5760 Final Project 项目说明 String Art起源于19世纪的数学…

信息系统项目管理师0044:IT治理方法与标准(3信息系统治理—3.1 IT治理—3.1.4 IT治理方法与标准)

点击查看专栏目录 文章目录 3.1.4 IT治理方法与标准1. ITSS中1T服务治理 3.1.4 IT治理方法与标准 考虑到IT治理对组织战略目标达成的重要性&#xff0c;国内外各类机构持续研究并沉淀IT治理相关的最佳实践方法、定义相关标准&#xff0c;这里面比较典型的是我国信息技术服务标准…