【C++】非类型模版参数以及模版的特化

目录

01.非类型模版参数

02.模版的特化

函数模版的特化

类模版特化


01.非类型模版参数

定义:

模版参数分为类型参数非类型参数

类型形参:跟在class或typename后面的参数类型名称,例如:

template <class T1, typename T2>
void printTypes() {
    std::cout << "Type 1: " << typeid(T1).name() << std::endl;
    std::cout << "Type 2: " << typeid(T2).name() << std::endl;
}

非类型形参:可以是整型、指针、引用、枚举等等,例如:

template <int N>
void printNTimes(const std::string& str) {
    for (int i = 0; i < N; ++i) {
        std::cout << str << std::endl;
    }
}

此处N就是非类型模版参数,它是一个整数。

常量表达式:

非类型模版参数必须是一个常量表达式,这意味着在编译时,必须能够确定其值

template<typename T, int N>
void print(vector<T> arr)
{
	for (int i = 0; i < N; i++) {
		cout << arr[i] << " ";
	}
	cout << endl;
}

int main()
{
	vector<int> arr{ 1,2,3,4,5,6,7,8,9,10 };
	print<int>(arr);
}

 此时编译不通过,因为没有定义N的值。也可以通过缺省参数的形式为N赋上初始值:

template<typename T, int N = 10>
void print(vector<T> arr)
{
	for (int i = 0; i < N; i++) {
		cout << arr[i] << " ";
	}
	cout << endl;
}
int main()
{
	vector<int> arr{ 1,2,3,4,5,6,7,8,9,10 };
	print<int>(arr);
}

多个非类型参数

模版类型形参中可以只有非类型参数,并且可以有多个,例如:

template<int weight = 5, int height = 5>
void print2()
{
	for (int i = 0; i < height; i++) {
		for (int j = 0; j < weight; j++) {
			cout << "*" <<" ";
		}
		cout << endl;
	}
}

int main()
{
	print2<5,10>();
}

这里的两个非类型参数分别表示打印矩阵的宽和高。

类型推导

在C++17中,非类型模版参数可以被推导:

template <auto Value>
void printValue() {
    std::cout << Value << std::endl;
}

printValue<42>();

这里的Value会被推导成int类型。

02.模版的特化

函数模版的特化

使用模版可以实现一些与类型无关的代码,但是对于一些特殊类型可能就会得到与预期不一致的结果,需要进行特殊化处理,比如:实现了一个用于"<"比较的模版函数:

template<typename T>
bool Less(T left, T right)
{
	return left < right;
}

class Date
{
public:
	Date(int year ,int month ,int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	bool operator<(Date& other)
	{
		if (_year != other._year) return _year < other._year;
		if (_month != other._month) return _month < other._month;
		return _day < other._day;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	cout << Less(1, 2) << endl; // 参数为整形,结果1

	Date d2(2004, 8, 22);
	Date d1(2024, 5, 8);
	cout << Less(d1,d2) <<endl; // 参数为类,结果0

	cout << Less(&d1, &d2) << endl; // 参数为类指针,结果1
}

可以看出,对int类型和Date类型的比较结果都正确,但是对于Date*类型,结果就出现了错误,这是因为编译器是对两者的地址大小进行比较,而我们希望对其本身进行比较,此时就需要对Date*这一类型特殊化处理

函数模板的特化步骤:

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

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

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

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

template<typename T>
bool Less<Date*>(Date* left, Date* right)
{
	return *left < *right;
}

类模版特化

1.全特化

全特化是指所有模版参数都进行特殊化处理:

template<typename T1, typename T2>
class Data
{
public:
	Date() { cout << "Date<T1, T2>" << endl; }
private:
	T1 d1;
	T2 d2;
};

template<>
class Data<int, char> // 全部特殊化处理
{
public:
	Data() { cout << "Date<int, char>" << endl; }
private:
	int d1;
	char d2;
};

2.偏特化

类模版的偏特化有两种表现形式:

  • 部分特化

将一部分参数进行特化:

template<typename T1>
class Data<T1, char>
{
public:
	Data() { cout << "Date<int, char>" << endl; }
private:
	T1 d1;
	char 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;    
};

这里并没有将参数特化成具体的数据类型,而是特化为指针、引用之类的复合类型。

总结:

模板特化的作用在一般模板无法满足特定类型或特定值的需求时,提供针对特定类型或特定值的定制化实现

以上就是关于模版的一些补充知识的整理了,欢迎在评论区留言,觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~😉

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

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

相关文章

模糊的图片文字,OCR能否正确识别?

拍照手抖、光线不足等复杂的环境下形成的图片都有可能会造成文字模糊&#xff0c;那这些图片文字对于OCR软件来说&#xff0c;是否能否准确识别呢&#xff1f; 这其中的奥秘&#xff0c;与文字的模糊程度紧密相连。想象一下&#xff0c;如果那些文字对于我们的双眼来说&#x…

sed小实践2(随手记)

删除/etc/passwd的第一个字符 #本质是利用sg替换&#xff0c;将第一个字符替换成空 sed s|^.||g /etc/passwd删除/etc/passwd的第二个字符 sed -r s|^(.).(.*$)|\1\2|g /etc/passwd sed -r s|^(.).|\1|g /etc/passwd删除/etc/passwd的最后一个字符 sed s|.$||g /etc/passwd删…

Java快速入门系列-11(项目实战与最佳实践)

第十一章&#xff1a;项目实战与最佳实践 11.1 项目规划与需求分析项目规划需求分析实例代码 11.2 系统设计考虑实例代码 11.3 代码实现与重构实例代码 11.4 性能优化与监控实例代码 11.5 部署与持续集成/持续部署(CI/CD)实例代码 11.1 项目规划与需求分析 在进行任何软件开发…

基于Vumat的修正JC本构模型的切削研究

JC渐进损伤本构是研究切削中的重要本构模型&#xff0c;主要包括材料硬化和损伤两部分&#xff1a;其中&#xff0c;原始JC的硬化部分本构为&#xff1b; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 材料屈服应力的硬化解耦为三部分独立的效应&#x…

blender导出gltf模型混乱

最近用户给了几个blender文件&#xff0c;在blender打开是这样的&#xff1a; 我导出成gltf候&#xff0c;在本地打开时&#xff0c;底部发生了改变&#xff1a; 可以看出来&#xff0c;底部由原来的类型box变为了两个平面&#xff0c;后来我查了下blender里的属性设置&#xf…

文件IO-使用dup2实现错误日志功能及判断文件权限,并终端输出

1&#xff1a;使用 dup2 实现错误日志功能 使用 write 和 read 实现文件的拷贝功能&#xff0c;注意&#xff0c;代码中所有函数后面&#xff0c;紧跟perror输出错误信息&#xff0c;要求这些错误信息重定向到错误日志 err.txt 中去 代码&#xff1a; #incl…

后教培时代的新东方,正在找寻更大的教育驱动力?

近段时间&#xff0c;K12教育主要上市公司的阶段性业绩皆已出炉。从具体数据来看&#xff0c;随着时间推移&#xff0c;教培机构的转型之路已愈走愈顺。 财报显示&#xff0c;2023年12月1日-2024年2月29日&#xff0c;好未来实现营收4.3亿美元&#xff0c;同比增长59.7%&#…

GIS 中的空间模式

空间模式显示了地球上事物的相互联系方式。这些图案可以是天然的或人造的。当我们使用 GIS 时&#xff0c;我们可以看到事物的位置以及它们之间的关系。今天&#xff0c;让我们关注地理和 GIS 领域的空间模式。 点分布的类型 点分布是将特定位置映射为地图上的单个点的方式。这…

W801学习笔记二十四:NES模拟器游戏

之前已经实现了NES模拟器玩游戏。W801学习笔记九&#xff1a;HLK-W801制作学习机/NES游戏机(模拟器) 现在要在新版本掌机中移植过来。 1、把NES文件都拷贝到SD卡中。 这回不会受内存大小限制了。我这里拷贝了4个&#xff0c;还可以拷贝更多。 2、应用初始化中&#xff0c;加载…

【运维网络篇】史上最全的 网络知识 思维导图!

01 TCP/IP网络协议栈 02 TCP/IP协议层次划分 03 传输介质简介 04 以太网帧结构 05 IP编址 06 ICMP协议 07 ARP协议 08 传输层协议 09 路由基础 10 静态路由基础 11 距离矢量路由协议——RIP 12 链路状态路由协议——OSPF 13 HDLC&PPP原理与应用 14 帧中继…

创新指南|创新组合管理的7个陷阱以及如何避免它们

进入未知领域的第一步可能具有挑战性。尽管创新会犯错误&#xff0c;但在将 IPM 作为公司实践实施时&#xff0c;您可以准备好并避免一些常见的陷阱。在这篇文章中&#xff0c;我们将讨论组织在实施创新组合管理时遇到的最常见的陷阱。 01. 在映射中包含日常业务任务 映射中的…

【iOS】-- 内存五大分区

【iOS】-- 内存五大分区 内存五大分区1.栈区优点&#xff1a; 2.堆区优点&#xff1a; 3.全局区4.常量区5.代码区 验证static、extern、const关键字比较1.static关键字static关键字的作用&#xff1a;全局静态变量局部静态变量 2.extern关键字对内的全局变量对外的全局变量 3.c…

Intel® Platform Firmware Resilience (Intel® PFR):英特尔® 平台固件恢复力(Intel® PFR)

为了降低与固件相关的安全风险&#xff0c;英特尔为服务器平台开发了英特尔平台固件恢复力&#xff08;Intel PFR&#xff09;。 此功能可保护关键固件在启动和运行时免受攻击。这可以被视为是 Cerberus 项目或 NIST SP800-193 的实现。 英特尔平台固件恢复力&#xff08;Int…

抖音小店是什么?它和直播带货有什么区别和联系?一篇详解!

大家好&#xff0c;我是电商糖果 在网上大家都说抖音的流量大&#xff0c;在抖音做电商比较赚钱。 可是有很多人对抖音电商并不了解。 甚至搞不懂抖音小店是什么&#xff1f;它和直播带货的区别和联系也不清楚。 下面&#xff0c;糖果就来给大家好好解答一下这个问题。 抖音…

Linux(openEuler、CentOS8)企业内网samba服务器搭建(Windows与Linux文件共享方案)

本实验环境为openEuler系统<以server方式安装>&#xff08;CentOS8基本一致&#xff0c;可参考本文) 目录 知识点实验1. 安装samba2. 启动smb服务并设置开机启动3. 查看服务器监听状态4. 配置共享访问用户5. 创建共享文件夹6. 修改配置文件7. 配置防火墙8. 使用windows…

C++中的右值引用和移动语义

目录 1 左值引用和右值引用 2 左值引用与右值引用比较 3 右值引用使用场景和意义 4 右值引用引用左值及其一些更深入的使用场景分析 5 完美转发 6.常数右边引用 1 左值引用和右值引用 传统的C语法中就有引用的语法&#xff0c;而C11中新增了的右值引用语法特性&#xff0c…

数组中两个字符串的最小距离

给定一个字符串数组strs&#xff0c;再给定两个字符串str1和str2&#xff0c;返回在strs中str1和str2的最小距离&#xff0c;如果str1或str2为null&#xff0c;或不在strs中&#xff0c;返回-1。 输入描述&#xff1a; 输入包含有多行&#xff0c;第一输入一个整数n(1 ≤ n ≤…

Python | Leetcode Python题解之第61题旋转链表

题目&#xff1a; 题解&#xff1a; class Solution:def rotateRight(self, head: ListNode, k: int) -> ListNode:if k 0 or not head or not head.next:return headn 1cur headwhile cur.next:cur cur.nextn 1if (add : n - k % n) n:return headcur.next headwhi…

【Redis7】了解Redis

1.常见数据库 1.1.键值存储数据库 如 Map 一样的key-value 对&#xff0c;典型代表就是 Redis。 1.2.列存储数据库 关系型数据库是典型的行存储数据库&#xff0c;按行存储的数据在物理层面占用的是连续存储空间&#xff0c;不适合海量数据存储。而按列存储则可实现分布式存储&…

第七届机电、机器人与自动化国际会议(ICMRA 2024)即将召开!

第七届机电、机器人与自动化国际会议&#xff08;ICMRA 2024&#xff09;将于2024年9月20日-22日在中国武汉举行。ICMRA 2024为各国专家学者提供一个学术交流的平台&#xff0c;讨论机电、机器人和自动化领域的最新研究成果和未来的研究方向&#xff0c;旨在能够建立起国家间&a…