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.mfbz.cn/a/592121.html

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

相关文章

Mac M2 本地下载 Xinference

想要在Mac M2 上部署一个本地的模型。看到了Xinference 这个工具 一、Xorbits Inference 是什么 Xorbits Inference&#xff08;Xinference&#xff09;是一个性能强大且功能全面的分布式推理框架。可用于大语言模型&#xff08;LLM&#xff09;&#xff0c;语音识别模型&…

激动,五四青年节,拿下YashanDB认证YCP

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 作者&#xff1a;IT邦德 中国DBA联盟(ACDU)成员&#xff0c;10余年DBA工作经验&#xff0c; Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主&#xff0c;全网粉丝10万 擅长主流Oracle、My…

中间件之搜索和数据分析组件Elasticsearch

一、概述 1.1介绍 The Elastic Stack, 包括 Elasticsearch、Kibana、Beats 和 Logstash&#xff08;也称为 ELK Stack&#xff09;。 能够安全可靠地获取任何来源、任何格式的数据&#xff0c;然后实时地对数据进行搜索、分析和可视 化。Elaticsearch&#xff0c;简称为 ES&a…

CUDA和显卡驱动

1.安装显卡驱动 https://www.nvidia.com/download/index.aspx?langen-us 由于我的显卡是RTX4060&#xff0c;因此先选择RTX40系列&#xff0c;然后选择RTX4060&#xff0c;进行安装 2.查看显卡对应的CUDA CUDA安装地址&#xff1a;https://developer.nvidia.com/cuda-toolk…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-12-蜂鸣器

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

复旦微JFM7VX690计算后IO接口模块,用于雷达信号处理、数据处理等需要高速密集计算的应用场景

计算后IO接口模块 1 介绍 1.1 产品概述 计算后IO接口模块主要由复旦微JFM7VX690型FPGA、国产以太网收发器YT8521、国产BMC芯片GD32F450、国产CPLD芯片EF2L45BG256B、国产内存颗粒等主要芯片组成&#xff0c;采用标准6U VPX尺寸设计。 本计算后IO接口模块主要用于雷达信号处…

QT+串口调试助手+基本版

一、创建串口调试助手UI界面 1、首先生成串口连接必要参数界面&#xff0c;删除关闭串口控件 2、给参数下拉框添加常见的选项&#xff0c;删除关闭串口控件 3、将串口调试助手参数界面布局整齐&#xff0c;删除关闭串口控件 4、更改控件名字&#xff0c;方便后续编程&#xff…

第五篇:通信脉络:探索计算机外设与总线体系的精髓

通信脉络&#xff1a;探索计算机外设与总线体系的精髓 1 引言 在这个技术日新月异的时代&#xff0c;理解计算机系统的基本构成要素 —— 总线和外设 —— 对于每个从事技术工作的人来说都是至关重要的。这些组件不仅是计算机通信的基石&#xff0c;也直接影响着系统的性能、效…

Universal Thresholdizer:将多种密码学原语门限化

参考文献&#xff1a; [LS90] Lapidot D, Shamir A. Publicly verifiable non-interactive zero-knowledge proofs[C]//Advances in Cryptology-CRYPTO’90: Proceedings 10. Springer Berlin Heidelberg, 1991: 353-365.[Shoup00] Shoup V. Practical threshold signatures[C…

关于MS-DOS时代的回忆

目录 一、MS-DOS是什么&#xff1f; 二、MS-DOS的主要功能有哪些&#xff1f; 三、MS-DOS的怎么运行的&#xff1f; 四、微软开源MS-DOS源代码 五、高手与漂亮女同学 一、MS-DOS是什么&#xff1f; MS-DOS&#xff08;Microsoft Disk Operating System&#xff09;是微软公…

多线程与信号量简介

信号量与 PV 操作 计算机中信号量的本质是整数&#xff0c;数值表示可用的资源数量 P 操作 (Passeren > 通过, 原子操作) 若信号量 0&#xff0c;当前任务阻塞 (进入信号量等待队列)若信号量 > 0&#xff0c;则&#xff1a;将信号量数值减一&#xff0c;当前任务继续执…

USP技术提升大语言模型的零样本学习能力

大语言模型&#xff08;LLMs&#xff09;在零样本和少样本学习能力上取得了显著进展&#xff0c;这通常通过上下文学习&#xff08;in-context learning, ICL&#xff09;和提示&#xff08;prompting&#xff09;来实现。然而&#xff0c;零样本性能通常较弱&#xff0c;因为缺…

KMP算法--C语言实现

#include <stdio.h> #include <assert.h> #include <string.h> #include <stdlib.h>void GetNext(char* sub, int next[]) {int lenSub strlen(sub);next[0] -1; // 初始第一个为 -1 第二个为 0next[1] 0;int i 2;int k 0;while (i < lenSub){…

探究Android的多分辨率支持以及各种类型图标尺寸大小

术语和概念 屏幕尺寸 屏幕的物理尺寸&#xff0c;以屏幕的对角线长度作为依据&#xff08;比如 2.8寸&#xff0c; 3.5寸&#xff09;。 简而言之&#xff0c; Android把所有的屏幕尺寸简化为三大类&#xff1a;大&#xff0c;正常&#xff0c;和小。 程序可以针对这三种尺寸…

使用UmcFramework和unimrcpclient.xml连接多个SIP设置的配置指南及C代码示例

使用UmcFramework和unimrcpclient.xml连接多个SIP设置的配置指南及C代码示例 引言1. UniMRCP和UmcFramework简介2. 准备工作3. unimrcpclient.xml配置文件3.1 定义SIP设置3.2 定义MRCP会话配置文件 4. C代码示例5. 测试和验证6. 故障排查7. 结论8. 参考文献 引言 在多媒体通信…

Vue单页面应用和多页面应用的区别

概念&#xff1a; SPA单页面应用&#xff08;SinglePage Web Application&#xff09;&#xff0c;指只有一个主页面的应用&#xff0c;一开始只需要加载一次js、css等相关资源。所有内容都包含在主页面&#xff0c;对每一个功能模块组件化。单页应用跳转&#xff0c;就是切换…

STM32标准库编译流程

导入库函数 在ST官方固件库中找到STM32F10x_StdPeriph_Lib_V3.5.0.zip文件&#xff0c;解压&#xff0c;打开Libraries,接着打开STM32F10x_StdPeriph_Driver文件夹&#xff0c;继续点击src&#xff0c;看到库函数源文件&#xff1a; 将其复制到keil建立的工程的文件中&#xf…

JAVA系列 小白入门参考资料 接口

目录 接口 接口的概念 语法 接口使用 接口实现用例 接口特性 实现多个接口和实现用例 接口间的继承 接口 接口的概念 在现实生活中&#xff0c;接口的例子比比皆是&#xff0c;比如&#xff1a;笔记本上的 USB 口&#xff0c;电源插座等。 电脑的 USB 口上&am…

在视频中使用时间卷积和半监督训练进行三维人体姿态估计

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 摘要Abstract文献阅读&#xff1a;在视频中使用时间卷积和半监督训练进行三维人体姿态估计1、文献摘要2、提出方法2.1、时间扩张卷积模型2.2、半监督方法2.3、与传统…

【错题集-编程题】十字爆破(预处理 + 模拟)

牛客对于题目链接&#xff1a;十字爆破 (nowcoder.com) 一、分析题目 暴力模拟会超时。 预处理&#xff0c;先把每一行以及每一列的和存起来。 模拟即可&#xff0c;但是由于数据量过⼤&#xff0c;我们可以提前把每⼀⾏以及每⼀列的和存起来&#xff0c;⽅便统计总和。 二、代…
最新文章