C++模版(高阶)

目录

非类型模版参数

模板特化

类模板全特化

类模板偏特化

函数模板全特化与偏特化

模板分离编译


非类型模版参数

前面的模版中,使用的都是针对对象类型设计的模版参数,从而便于编译器针对不同类型推演出不同类型的函数或者类

但是有一种模版参数比较特殊,即非类型模版参数,有以下特点:

  1. 只可以定义为整型类型的常量
  2. 非类型的模板参数必须在编译期就能确认结果

示例代码:

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

在上面的代码中,T即为类型模板参数,而N即为非类型模板参数,并且因为size_t代表无符号整型,所以属于整型系列,编译通过

非类型模板参数主要使用在为数组开辟空间,当需要使用该类中的数组时,可以使用默认的10作为数组大小,也可以自定义N的大小从而确定数组的大小

在C++11中,新增了一个容器名为array,底层就是对数组进行了一个封装,目的是方便处理数组的相关问题,比如越界访问

array容器的定义:

template < class T, size_t N > class array;

原来的数组是C类型的数组,该数组对越界访问的控制并不严格,甚至有时并不能发现是越界访问,所以针对这个问题,C++11添加了array容器,从而更好地处理越界访问等问题

模板特化

在C++中,除了可以对任意类型使用模板以外,还可以使用模板特化来针对某一种类或者函数提供特殊的模板

模板特化分为全特化和偏特化,而对于类和函数来说,也分为类模板全特化和偏特化以及函数模板全特化和偏特化

函数模板的特化步骤:

  1. 必须要先有一个基础的函数模板
  2. 关键字template后面接一对空的尖括号<>
  3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
  4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。

类模板全特化

所谓全特化,即特化的模板参数类型全部用指定的类型替换普通模板中的类型

例如下面的代码:

#include <iostream>
using namespace std;//普通模板
template<class T1, class T2>
class A
{
public:A(T1 val1, T2 val2):num1(val1), num2(val2){}private:T1 num1;T2 num2;
};//全特化为int类型
template<>
class A<int, int>
{
public:A(int val1, int val2):num1(val1),num2(val2){}private:int num1;int num2;
};int main()
{A<double, int> a(1.9, 2);//调用普通模板A<int, int> a1(1, 2);//调用全特化模板return 0;
}

在上面的代码中,针对int类型使用了全特化的类,此时如果使用两个int类型的值创建对象,那么编译器会直接调用全特化的类进行构造

此时考虑下面的仿函数

//仿函数
template<class T>
class less
{
public:bool operator()(T val1, T val2){return val1 < val2;}
};

对于int类型,double类型这种普通的数值类型来说,直接比较并不会有什么问题(此处不考虑浮点数精度问题),但是如果为指针类型,那么比较方式会有不同,因为比较指针除了比较二者地址以外,还有比较指针指向的内容,而对于上面的比较大小的仿函数,如果直接将指针类型作为模板参数,那么比较的就是指针本身存的地址,如果此时想比较指针指向的内容时就需要用到全特化,参考下面的代码:

//仿函数
//Date为自定义类型,并且已经重载*和<
template<>
class less<Date*>
{
public:bool operator()(Date* val1, Date* val2){return *val1 < *val2;}
};

类模板偏特化

对比全特化,偏特化就是只有一部分是指定的类型,其余的部分还是普通的模板参数类型,例如下面的代码:

//偏特化为T和int类型
template<class T>
class A<T, int>
{
public:A(T val1, int val2):num1(val1), num2(val2){}private:T num1;int num2;
};

在上面代码中,只要第二个模板参数类型时int类型时,就会走偏特化构造函数

现在有了下面三种模板:

//普通模板
template<class T1, class T2>
class A
{
public:A(T1 val1, T2 val2):num1(val1), num2(val2){}private:T1 num1;T2 num2;
};//全特化为int类型
template<>
class A<int, int>
{
public:A(int val1, int val2):num1(val1),num2(val2){}private:int num1;int num2;
};//偏特化为T和int类型
template<class T>
class A<T, int>
{
public:A(T val1, int val2):num1(val1), num2(val2){}private:T num1;int num2;
};

下面有三个对象:

A<double, double> a1(1.2, 1.2);//调用普通模板
A<int, int> a2(1, 2);//调用全特化模板
A<double, int> a3(1.9, 2);//调用偏特化

因为doubledouble类型没有偏特化和全特化,所以走普通模板,而intint类型有全特化,所以走全特化模板,对于doubleint类型,因为有偏特化,所以走偏特化模板

所以在普通模板、偏特化模板和全特化模板中,匹配顺序依次是:

  1. 全特化
  2. 偏特化
  3. 普通模板

函数模板全特化与偏特化

函数模板的全特化与偏特化方式参考下面的代码:

//普通函数模板
template<class T1, class T2>
T1 add(T1 val1, T2 val2)
{return val1 + val2;
}//全特化函数模板
template<>
int add<int, int>(int val1, int val2)
{return val1 + val2;
}//偏特化函数模板
template<class T>
T add<int, T>(int val1, int val2)
{return val1 + val2;
}

但是对于函数模板来说,一般不需要用到特化,只需要用函数重载+最匹配原则即可

模板分离编译

在C++中本身是不支持模板的声明和定义分别放在两个文件中,所以一般的处理方式有以下两种:

  1. 不写声明直接定义放在.h文件中
  2. 将声明写在定义之前,一般放在.hpp文件中

📌

一般的.hpp文件即为声明和定义在一起,表示该文件中既有类和函数模板的声明,也有对应的定义

例如下面的.hpp文件

//函数模板声明
template<class T>
T Add(const T& left, const T& right);//普通函数声明
void func();//类模板声明
template<class T>
class Stack 
{
public://成员函数声明void Push(const T& x);void Pop();
private:T* _a = nullptr;int _top = 0;int _capacity = 0;
};//函数模板定义
template<class T>
T Add(const T& left, const T& right)
{cout << "T Add(const T& left, const T& right)" << endl;return left + right;
}//普通函数定义
void func()
{cout << "void func()" << endl;
}//成员函数定义
template<class T>
void Stack<T>::Push(const T& x)
{cout << "void Stack<T>::Push(const T& x)" << endl;
}//成员函数定义
template<class T>
void Stack<T>::Pop()
{cout << "void Pop()" << endl;
}

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

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

相关文章

返回链表的中间节点题目讲解(超快方法)

一&#xff1a;题目 二&#xff1a;思路讲解 采用快慢指针方法来解决 1&#xff1a;slow指针一次跳一个节点&#xff0c;fast指针一次跳两个节点&#xff0c;这样当fast到尾节点的时候&#xff0c;slow刚好到中间节点&#xff0c;但是奇数个的时候&#xff0c;fast不会刚好的…

Laravel - 数组函数

引入包 use Illuminate\Support\Arr; 一、检查给定的值是否可数组式访问 Arr::accessible([a > 1, b > 2]);// true 二、数组添加 Arr::add([name > Desk], price, 100) ;// [name > Desk, price > 100] Arr::add([name > Desk, price > null], price…

电子元器件商城如何建设

建设一个成功的电子元器件商城需要考虑以下几个方面&#xff1a; 1. 明确目标市场和用户需求 确定目标客户群是个人爱好者、小型企业还是大型制造商&#xff1f;了解目标客户群对电子元器件的需求特点&#xff0c;例如价格、质量、品牌、规格、技术支持等。 2. 选择合适的电…

Seal^_^【送书活动第3期】——《Hadoop大数据分析技术》

Seal^_^【送书活动第3期】——《Hadoop大数据分析技术》 一、参与方式二、作者荐语三、图书简介四、本期推荐图书4.1 前 言4.2 本书内容4.3 本书目的4.4 本书适合的读者4.5 配套源码、PPT课件等资源下载 五、目 录六、&#x1f6d2; 链接直达 Hadoop框架入门书&#xff0c;可当…

async详解

async(1): cpp20协程基础-CSDN博客async(2)concept与辅助类-CSDN博客async(3)句柄、Selector、EventLoop-CSDN博客async(4) 返回值-CSDN博客async(5) 封装-CSDN博客async(6) &#xff08;批量&#xff09;等待-CSDN博客async(7) 网络相关-CSDN博客

语言模型测试系列【7】

语言模型 文心一言星火认知大模型通义千问豆包360智脑百川大模型腾讯混元助手Kimi Chat商量C知道 今天看CSDN文章&#xff0c;看到了斐波那契数列这个有趣的数列计算&#xff0c;然后就在文心一言中对答了一波&#xff0c;给的答案很完整&#xff0c;而且给出来python的实现代…

Golang | Leetcode Golang题解之第69题x的平方根

题目&#xff1a; 题解&#xff1a; func mySqrt(x int) int {if x 0 {return 0}C, x0 : float64(x), float64(x)for {xi : 0.5 * (x0 C/x0)if math.Abs(x0 - xi) < 1e-7 {break}x0 xi}return int(x0) }

沟通【说明事物、表达情感、建立关系、进行企图】

沟通目的&#xff1a; 说明事物表达情感建立关系进行企图 缘解释为&#xff1a;机会 or 关系 沟通是有来有往&#xff0c;你来几句&#xff0c;我来几句。 我讲几句&#xff0c;停下来&#xff0c;有反应 沟通结果&#xff1a;产生一起的行动 第一句话是先认同他【先赞成&a…

【GUI软件】调用YouTube的API接口,采集关键词搜索结果,并封装成界面工具!

文章目录 一、背景介绍1.1 爬取目标1.2 演示视频1.3 软件说明 二、代码讲解2.1 调用API-搜索接口2.2 调用API-详情接口2.3 API_KEY说明2.4 软件界面模块2.5 日志模块 三、获取源码及软件 一、背景介绍 1.1 爬取目标 您好&#xff01;我是马哥python说&#xff0c;一名10年程序…

D盘被格式化了能找回吗 d盘格式化了数据可以找回来吗

D盘作为电脑中重要的磁盘之一&#xff0c;很多用户都会将一些重要的数据保存在D盘。但在磁盘空间不足的情况下&#xff0c;或许有些用户会将其进行格式化&#xff0c;D盘被格式化了如何恢复数据&#xff1f; 如果是比较重要的数据&#xff0c;建议用户立即进行数据恢复操作&am…

Ansible之Playbook的Template模板和tags标签

文章目录 一、Template模块1、准备template模板文件2、修改主机清单文件3、编写playbook4、执行playbook5、准备测试网页6、访问测试 二、tags模块1、编写脚本2、执行tags"xx01"3、执行tags"xx02" 一、Template模块 Jinja是基于Python的模块引擎。Templat…

小米手机怎么截屏?一篇文章教会你!

我们经常需要截取手机屏幕上的内容&#xff0c;无论是为了分享、教学还是记录。对于小米手机用户来说&#xff0c;掌握截屏技巧不仅能够方便地记录精彩瞬间&#xff0c;还能在需要时轻松分享或保存屏幕内容。小米手机怎么截屏&#xff0c;有哪些截屏方式呢&#xff1f;本文将为…

执行 .sh文件报错

执行.sh文件报错&#xff1a;: ▒▒▒Ǹ▒▒ļ▒▒▒Ŀ1 ▒▒&#x1f4bf; . ./start.sh 修改 vim vim /etc/profileexport LC_ALLzh_CN.GBK export LANGzh_CN.GBK #修改成下面的 export LC_ALLzh_CN.UTF-8 export LANGzh_CN.UTF-8执行命令source /etc/profile如果还报$等符号…

TesseractOCR安装及使用

1. 基本概念 1.1 Tesseract Tesseract 是一款基于 C 语言开发并开源的光学识别工具&#xff0c;提供底层的文字识别能力。 1.2 Tess4J Tess4J 是对 Tesseract OCR API 的 Java 封装&#xff0c;有了 Tess4J 之后 Java 就可以直接调用本地安装的 Tesseract 进行文字识别。 …

408数据结构总结复习笔记一:线性表

408数据结构总结复习笔记一&#xff1a;线性表 从现在开始慢慢更新我的考研复习笔记系列吧~ PS&#xff1a;主要是我自己个人复习过程中觉得重点的点&#xff0c;大家仅供参考哈~ 上岸&#xff01;&#xff01;&#xff01;大家一起加油! 顺序表和链表的比较 顺序表链表存取…

前端GET请求下载后端返回数据流文件,并且处理window.open方法跳转白屏方法

平时常用导出都是用window.open方法 点击跳转连接&#xff1a;使用 window.open 下载 const downError 地址?&参数${参数|| }; const downError Url/xxx/xxx?&orgId${orgId || };window.open(downError, "_self");//调用window.open方法导出 而使用…

idea快捷键被占用,如何解决ctrl+\ 为例

本来这个这个快捷键ctrl\ 是只有restful 插件才生效的&#xff0c;但是idea升级了之后&#xff0c;多了个 AI Assistant 这样他也有个快捷键是这个&#xff0c; 所以 需要借助 settings - keymap - 直接找到右边的放大镜&#xff0c;可以输入快捷键查询 把ai 那个啥玩意…

从零手写实现 tomcat-04-请求和响应的抽象

创作缘由 平时使用 tomcat 等 web 服务器不可谓不多&#xff0c;但是一直一知半解。 于是想着自己实现一个简单版本&#xff0c;学习一下 tomcat 的精髓。 系列教程 从零手写实现 apache Tomcat-01-入门介绍 从零手写实现 apache Tomcat-02-web.xml 入门详细介绍 从零手写…

什么是香草看涨期权?香草看涨期权有哪些特点?

什么是香草看涨期权&#xff1f;香草看涨期权有哪些特点&#xff1f; 香草看涨期权&#xff0c;通常也称为香草期权&#xff0c;是金融市场上的一种金融衍生品&#xff0c;由券商或金融机构推出。它允许投资者以较小的费用获取相应股票市值的收益权&#xff0c;主要用于风险管…

Python爬虫获取豆瓣电影Top100

大家好&#xff0c;我是秋意零。 今天分析一篇&#xff0c;Python爬虫获取豆瓣电影Top100。 在此之前&#xff0c;我没有学习过爬虫&#xff0c;只有一丢丢的Python基础。下面效果的实现源码几乎没经过我&#xff0c;而是AI百老师。我主要负责了对应的调试以及根据我想要的功…