解剖C++模板(2) —— 模板匹配规则及特化

        众所周知,模板声明部分的尖括号中的内容是声明模板形参,而调用模板时的尖括号是给模板传参。然而这样理解仅仅停留于现象,只是将模板形参传参和函数传参的过程划等号了。C++ 的函数重载匹配并非真的进行匹配,因为函数名修饰规则导致重载总能第一时间找到匹配的函数。而模板不同,对模板传参进行实例化过程中,模板匹配的过程是真实发生的。

        先谈实例化条件。实例化条件不同,即使模板标识符相同,也会被当作不同模板。对应的就是实例化模板时的匹配规则。这里需要分清实例化条件和匹配规则。匹配规则是根据不同模板所要求的实例化条件,对模板实例化语句进行条件查找,以找到最合适的模板进行实例化。

        对于不同类别的模板,对多个同名模板实例化条件的要求也各不相同,实际上对应的就是匹配规则的不同。我们先谈实例化条件的要求,也就是同名模板中尖括号的规则。

1、函数模板

1、函数模板规则

        函数模板的实例化条件是最宽松的,同样数量的模板形参,但类别不同,依然当作不同模板处理。模板形参个数不同也会被当作不同模板(其中讲类当作模板参数必须 C++20 以上才支持)。这一切都是为了配合函数重载。函数模板支持以类型推导来隐式实例化,也正因为如此,函数模板的规则是最麻烦的一种,它的理解有别于其他模板,甚至可以说与其他模板的实例化规则不是同一套(具体等谈完其他类别模板之后再细说)。

        因为函数模板对实例化条件的要求过于宽松,加上模板由于有默认模板形参的存在,类比于函数重载会引发重载歧义,函数模板也会引发模板实例化歧义。

2、为什么函数模板没有偏特化

         基于以上所提及的特性,模板没有偏特化的第一个原因:对于指定其中某个模板形参的这种偏特化,函数模板压根不需要这种形式。原因如下图:

        这不就是模板偏特化么?只是不支持像类模板那种偏特化写法罢了。

        至于第二种偏特化,即对传入类型加以限定的偏特化,许多情况下都会导致编译器无法判断以原始模板还是偏特化进行实例化。先看个例子,虽然这个例子并不贴切。

        也就是说,当你不显式指明函数模板形参时,编译器根本无法判断你是想传值还是传引用。假如此时你对模板形参以引用进行限定偏特化,编译器如何判断你传入的右值函数参数是要传值还是传引用?应该选择哪个版本进行实例化?毕竟函数传引用和传值都是特别常见的操作,根本不存在优先级。除了引用问题,const 偏特化也是一样的情况,可自行类比于下图的函数重载歧义。

        总结来说函数模板之所以没有偏特化一部分原因是不需要,另一部分原因是做不到。归根结底还是由于函数模板对类型推导的支持所导致。

2、其他模板

        这部分我们以类模板作为典型,其他模板也是一样的规则。

1、类模板规则

        将刚才的函数模板直接改为类模板会发现编译根本通不过。

        这源于类模板是显示写明模板参数的。在模板实例化开始时,会将所有模板添加到模板匹配列表里。类模板与函数模板不同的是,同名模板在匹配列表中只允许存在一个,并且写在前面的模板会排斥后续的同名模板。以下三张截图就足以清洗说明这一点。

        ① 和 ② 说明两个同名模板的模板形参个数不同,编译器将写在前面的同名模板添加到匹配队列,导致后面的模板压根进入不了匹配队列,因此编译器只认识前面的模板,故而会提示模板形参太多或者缺少模板形参。 ③ 之中,两个同名模板的模板形参个数也相同,但形参类型不同。但不管是哪种情况,编译器只会将第一个模板添加到匹配队列中。

2、类模板的全特化和偏特化

        毕竟类模板实例化必须要显式传递模板参数,它的匹配规则并不需要像函数模板一般复杂。不论是全特化还是偏特化,只要显式写明模板参数就不会造成歧义。如同函数模板中 foo<int&&>(std::move(n)) 的例子一样。

        前面提到的类模板的同名模板在匹配列表中只允许存在一个。而全特化偏特化则是添加一个限制后的与主模板同名的模板到匹配列表中。事实上我们完全可以如同函数模板一般,将偏特化当作一个新的同名模板

3、变量模板和约束

        这里仅作展示,匹配规则与类模板是一样的。

        可见约束和类模板一样,只允许有一个同名约束。

        对于变量模板,VS 甚至会在书写模板时就对第二个同名模板报错。 

4、总结

        以上结论,模板应该区分为函数模板和非函数模板,他们的匹配规则是不同的。而匹配规则便是尖括号中的内容,它对模板实例化起决定作用。

        文中还提到匹配列表,它是如何运作的,后续有机会再谈。

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

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

相关文章

题目讲解15 合并两个排序的链表

原题链接&#xff1a; 合并两个排序的链表_牛客题霸_牛客网 思路分析&#xff1a; 第一步&#xff1a;写一个链表尾插数据的方法。 typedef struct ListNode ListNode;//申请结点 ListNode* BuyNode(int x) {ListNode* node (ListNode*)malloc(sizeof(ListNode));node->…

高性能Web网关:OpenResty 基础讲解

一&#xff1a;概述 OpenResty是由国人章亦春开发的一个基于Nginx的可伸缩的Web平台。 openresty 是一个基于 nginx 与 lua 的高性能 web 平台&#xff0c;其内部集成了大量精良的 lua 库、第三方模块以及大数的依赖项。用于方便搭建能够处理超高并发、扩展性极高的动态 web 应…

OceanBase JDBC (Java数据库连接)的概念、分类与兼容性

本章将介绍 OceanBase JDBC的 概念与分类&#xff0c;已帮助使用 JDBC 的用户及技术人员更好的 了解JDBC&#xff0c;以及 OceanBase JDBC在与 MySQL 及 Oracle 兼容性方面的相关能力。 一、JDBC 基础 1.1 JDBC 的概念 JDBC 一般指 Java 数据库连接。Java 数据库连接&#xf…

关于Django 模型字段 `choices`自定义数据类型的枚举——补充

文章目录 1. 处理 datetime 类型的 choices2. 处理 time 类型的 choices3. 处理 Decimal 类型的 choices4. 处理 UUID 类型的 choices5. 处理 float 类型的 choices 在 Choices 类的基础上扩展&#xff0c;可以将 choices 与特定数据类型&#xff08;如 date 或 datetime&a…

小程序中引入下载到本地的iconfont字体图标加载不出来问题解决

我这个是uniapp项目,字体图标都是一样的,在vue项目中web端、uniapp运行到h5都没问题,但是运行到小程序加载不出来,报错如下: 不让用本地路径,所以我们要转为base64编码,这里给大家提供一个工具,它可以把本地字体文件转为base64:transfonter 进入官网后,第一步: …

如何在 Ubuntu 24.04 上安装和配置 Fail2ban ?

确保你的 Ubuntu 24.04 服务器的安全是至关重要的&#xff0c;特别是如果它暴露在互联网上。一个常见的威胁是未经授权的访问尝试&#xff0c;特别是通过 SSH。Fail2ban 是一个强大的工具&#xff0c;可以通过自动阻止可疑活动来帮助保护您的服务器。 在本指南中&#xff0c;我…

大模型论文精华—20241111

使用大型语言模型进行神经病理诊断的初步探索 研究问题 本研究探讨了大型语言模型&#xff08;LLMs&#xff09;在辅助医生进行神经病理学诊断中的潜在应用。具体来说&#xff0c;研究人员通过设计特定的问题和病例背景&#xff0c;询问多个流行的LLMs&#xff0c;并根据这些…

量化交易系统开发-实时行情自动化交易-3.4.2.2.Okex交易数据

19年创业做过一年的量化交易但没有成功&#xff0c;作为交易系统的开发人员积累了一些经验&#xff0c;最近想重新研究交易系统&#xff0c;一边整理一边写出来一些思考供大家参考&#xff0c;也希望跟做量化的朋友有更多的交流和合作。 接下来聊聊基于Okex交易所API获取交易数…

多商户中英双语电商系统设计与开发 PHP+mysql

随着全球电商市场的扩展&#xff0c;多商户平台成为了越来越多商家参与全球贸易的重要方式。为了适应不同语言用户的需求&#xff0c;尤其是中英双语用户的需求&#xff0c;设计一个支持中英双语的电商系统显得尤为重要。本文将重点探讨如何设计一个多商户中英双语电商系统&…

关于 3D Engine Design for Virtual Globes(三维数字地球引擎设计)

《3D Engine Design for Virtual Globes》是一本专注于三维虚拟地球引擎设计的专业书籍。这本书由Patrick Cozzi和Kevin Ring编写&#xff0c;覆盖了设计适用于虚拟球面环境的三维引擎的各个方面。虚拟地球引擎作为地理信息系统&#xff08;GIS&#xff09;中的一个核心组件&am…

ubuntu 20.04添加ros官方的软件源(解决下载ros软件包出现的E 无法定位软件包的问题)

ubuntu 20.04添加ros官方的软件源&#xff08;解决下载ros软件包出现的E: 无法定位软件包的问题&#xff09; 在 Ubuntu 20.04 上添加 ROS 官方软件源可以解决使用其他镜像源时遇到的 “E: 无法定位软件包” 的问题&#xff0c;主要是因为这些镜像源可能没有同步所有官方提供的…

单元测试、集成测试、系统测试有什么区别

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 单元测试、集成测试、系统测试有什么区别 1、粒度不同 集成测试bai粒度居中&#xff0c;单元测试粒度最小&#xff0c;系统du测试粒度最大。 2、测试方式不同…

CE2.【C++ Cont】练习题组2

1.数字反转 https://www.luogu.com.cn/problem/P5705 题目描述 输入一个不小于 100100 且小于 10001000&#xff0c;同时包括小数点后一位的一个浮点数&#xff0c;例如 123.4123.4 &#xff0c;要求把这个数字翻转过来&#xff0c;变成 4.3214.321 并输出。 输入格式 一行一个…

Golang | Leetcode Golang题解之第557题反转字符串中的单词III

题目&#xff1a; 题解&#xff1a; func reverseWords(s string) string {length : len(s)ret : []byte{}for i : 0; i < length; {start : ifor i < length && s[i] ! {i}for p : start; p < i; p {ret append(ret, s[start i - 1 - p])}for i < le…

适合二开的web组态?

一、web组态的定义和背景 在深入探讨之前&#xff0c;我们先回顾一下“组态”的定义。在工业自动化领域&#xff0c;组态软件是用于创建监控和数据采集&#xff08;SCADA&#xff09;系统的工具&#xff0c;它允许工程师构建图形界面&#xff0c;实现与各种设备和机器的数据交互…

L1-4【练习7-11】 字符串逆序

输入一个字符串&#xff0c;对该字符串进行逆序&#xff0c;输出逆序后的字符串。 输入格式&#xff1a; 输入在一行中给出一个不超过80个字符长度的、以回车结束的非空字符串。 输出格式&#xff1a; 在一行中输出逆序后的字符串。 输入样例&#xff1a; Hello World!输…

【大数据学习 | HBASE】hbase的读数据流程与hbase读取数据

1. hbase的读数据流程 在解析读取流程之前我们还需要知道两个功能性的组件和HFIle的格式信息 HFILE 存储在hdfs中的hbase文件&#xff0c;这个文件中会存在hbase中的数据以kv类型显示&#xff0c;同时还会存在hbase的元数据信息&#xff0c;包括整个hfile文件的索引大小&…

使用 nsenter 进入 Docker 容器的操作

在容器化环境下&#xff0c;docker exec 通常是进入容器内部进行调试的常用方式&#xff0c;但在某些情况下&#xff0c;比如 Docker 容器管理工具出现问题&#xff0c;或者我们需要通过进程的命名空间来直接访问容器&#xff0c;nsenter 就成了一个非常有效的工具。本文将介绍…

什么是聚类分析,它在数据分析中的应用是什么

聚类分析是一种无监督学习方法&#xff0c;它旨在将数据集中的样本按照某种相似性准则自动进行分组。聚类分析的目标是将相似的样本划分为同一个簇&#xff0c;同时将不同簇之间的样本尽可能分离开。聚类分析的结果通常用簇的标签来表示&#xff0c;簇标签表示样本所属的簇。 …

MySQL 忘记 root 密码,使用跳过密码验证进行登录

MySQL 忘记 root 密码&#xff0c;使用跳过密码验证进行登录 修改 /etc/my.cnf 配置文件&#xff0c;在 [mysqld] 后面任意一行添加 skip-grant-tables vim /etc/my.cnf 重启 MySQL systemctl restart mysqld 登录 MySQL&#xff08;无 -p 选项&#xff0c;无需密码登录&…