当前位置: 首页 > news >正文

【C++】模板与泛型编程(三):重载与模板

16.3 重载与模板

函数模板可以被另一个模板或一个普通分模板函数重载。与往常一样,名字相同的函数必须具有不同数量或类型的参数(这样才可以完成重载)。

如果设计模板,则函数的匹配规则与普通函数的重载有所不同,具体来说,当涉及模板时:

  • 对于一个调用,其候选函数包括所有模板实参推断成功的函数模板实例
  • 候选的函数模板总是可行的,因为模板实参推断会排除任何不可行的模板;
  • 与往常一样,可行函数(模板与非模板)按类型转换(如果对此调用需要的话)来排序;
  • 与往常一样,如果恰有一个函数提供比任何其它函数都更好的匹配,则选择此函数。如果出现多个匹配,则选择更好的那一个。如果有多个更好的,则此调用有歧义。

编写重载模板

下例构造一组函数,命名为 debug_rep,每个函数返回一个给定对象的 string 表示。

首先编写该函数最通用的版本,将它定义为一个模板,接受一个 const 对象的引用:

template <typename T> string debug_rep(const T &t) {ostringstream ret;ret << t;return ret.str();
}

接下来定义打印指针的 debug_rep 版本:

template <typename T> string debug_rep(T *p) {ostringstream ret;ret << "pointer: " << p;	// 打印指针的值if(p) {ret << " " << debug_rep(*p);	// 打印 p 指向的值	} else {ret << "null pointer";			// 或打印为空指针}return ret.str();
}

调用上述的两个函数:

string s("hi!");
cout << debug_rep(s) << endl;	// 调用第一个版本的 debug_rep, 实参是 string
cout << debug_rep(&s) << endl;	// 调用第二个版本的 debug_rep, 实参是 string*

对于第二个函数调用,编译器将会生成两种版本的模板函数实例,实际上,第二个函数调用可以与上述两个模板函数都进行绑定,实例化的结果如下:

debug_rep(const string*&);	// 由第一个版本的 debug_rep 实例化而来, T 被绑定到 string*
debug_rep(string*);			// 由第二个版本的 debug_rep 实例化而来, T 被绑定到 string

第二个实例化的结果是第二个函数调用的精准匹配。

多个可行模板

另一个例子进行如下调用:

const string *sp = &s;
cout << debug_rep(sp) << endl;

对于这个例子,上述两个版本的模板都是可行的,而且两个都是精准匹配。

在此情况下,正常的函数匹配规则无法区分这两个函数,但根据重载函数模板的特殊规则,此调用被解析为debug_rep(T*),即:更特例化的版本。debug_rep(const T&)本质上适用于任何类型,包括指针类型,它比debug_rep(T*)更加通用,后者只能由于指针类型。因此,用自己的话说就是,重载模板匹配的规则大概可以概括为,当存在多个适配的函数匹配时,选择最不通用,最没有歧义,最匹配的那一个

非模板和模板重载

这个例子定义一个普通非模板的 debug_rep 来打印双引号包围的 string:

string debug_rep(const string &s) {return '"' + s + '"';
}

调用时:

string s("hi!");
cout << debug_rep(s) << endl;

有两个同样好的可行函数:

debug_rep<string>(const string&);	// 第一个模板, T 绑定到 string*
debug_rep(const string&);			// 普通非模板函数

显然,二者提供相同的参数列表,可以认为二者提供同样好的匹配。但是,根据编译器的规则,它将会选择非模板的版本进行匹配。当存在多个同样好的函数模板时,编译器选择最特例化的版本,处于同样的原因,一个非模板会比一个函数模板更好。

重载模板和类型转换

对于 C 风格字符串指针以及字符串字面常量,考虑如下调用:

cout << debug_rep("hi world!") << endl;	// 调用 debug_rep(T*)

本例中所有三个 debug_rep 都是可行的:

debug_rep(const T&);		// T 绑定到 char[10]
debug_rep(T*);				// T 绑定到 const char
debug_rep(const string&);	// 要求从 const char* 到 string 的类型转换

对于给定的实参,两个模板都提供精确匹配——第二个模板需要进行一次(许可的)数组到指针的转换,而对于函数匹配来说,这种转换被认为是精确匹配。非模板版本是可行的,但需要进行一次用户定义的类型转换。与之前一样,T*版本更加特例化,编译器会选择它。

如果我们希望字符指针按照 string 处理,可以定义另外两个非模板重载版本:

string debug_rep(char *p) {return debug_rep(string(p));
}
string debug_rep(const char *p) {return debug_rep(string(p));
}

缺少声明可能导致程序行为异常

值得注意的是,为了使 char * 版本的 debug_rep 正确工作,在定义此版本时,debug_rep(const string&)的声明必须在作用域中。否则,就有可能调用错误的 debug_rep 版本,比如模板实例化的版本:

template<typename T> string debug_rep(const T &t);
template<typename T> string debug_rep(T *p);
string debug_rep(const string&);
string debug_rep(char *p) {// 如果第三个函数声明不在当前作用域中, 那么下面的 debug_rep 将调用 debug_rep(const T&)实例化的版本return debug_rep(string(p));
}

在定义任何函数之前,记得声明所有重载的函数版本。这样就不用担心编译器由于未遇到你希望调用的函数而实例化一个并非你需要的版本。

相关文章:

【C++】模板与泛型编程(三):重载与模板

16.3 重载与模板 函数模板可以被另一个模板或一个普通分模板函数重载。与往常一样&#xff0c;名字相同的函数必须具有不同数量或类型的参数&#xff08;这样才可以完成重载&#xff09;。 如果设计模板&#xff0c;则函数的匹配规则与普通函数的重载有所不同&#xff0c;具体…...

JavaScript字符串拓展:实用方法与示例全解析

一、引言&#xff1a;为什么要学习 JS 字符串拓展 在前端开发的世界里&#xff0c;JavaScript 如同基石般支撑着网页的交互与动态呈现。而字符串作为我们日常操作中最频繁接触的数据类型之一&#xff0c;其原生方法在面对复杂多变的业务需求时&#xff0c;有时难免显得捉襟见肘…...

基于html5实现音乐录音播放动画源码

源码介绍 基于html5实现音乐录音播放动画源码是一款类似Shazam的UI&#xff0c;点击按钮后&#xff0c;会变成为一个监听按钮。旁边会有音符飞入这个监听按钮&#xff0c;最后转换成一个音乐播放器。 效果预览 源码获取 基于html5实现音乐录音播放动画源码...

初学stm32 --- ADC模拟/数字转换器工作原理

目录 常见的ADC类型 并联比较型工作示意图 逐次逼近型工作示意图 ADC的特性参数 STM32各系列ADC的主要特性 ADC框图简介 参考电压/模拟部分电压 输入通道&#xff08; F1为例&#xff09; 转换序列&#xff08;F1为例&#xff09; 规则组和注入组执行优先级对比 规则…...

导航技术的分类

导航技术可以根据不同的分类标准进行划分&#xff0c;以下是从不同角度对导航技术的分类&#xff1a; 一、按导航信息获取原理分类 无线电导航&#xff1a;利用无线电波的传播特性来测定运动体的位置、速度等导航参数。常见的无线电导航系统包括罗兰-C、奥米加、台卡等。卫星…...

C++语言的函数实现

C语言中的函数实现详解 C是一种强大的编程语言&#xff0c;广泛应用于系统软件、游戏开发、实时物理模拟等多个领域。在C中&#xff0c;函数是组织和重用代码的重要工具。本文将深入探讨C中的函数实现&#xff0c;包括函数的定义、调用、重载、递归、作用域、内联函数和模板函…...

每日一题-两个链表的第一个公共结点

文章目录 两个链表的第一个公共结点问题描述示例说明示例 1示例 2 方法及实现方法描述代码实现 复杂度分析示例运行过程示例 1示例 2 总结备注 两个链表的第一个公共结点 问题描述 给定两个无环的单向链表&#xff0c;找到它们的第一个公共节点。如果没有公共节点&#xff0c…...

细说STM32F407单片机以轮询方式读写外部SRAM的方法

目录 一、实例的功能 二、工程配置 1、KEYLED 2、时钟、DEBUG、USART6、NVIC、GPIO、CodeGenerator 3、FSMC &#xff08;1&#xff09; 模式设置 &#xff08;2&#xff09; Bank 1子区3参数设置 1) NOR/PSRAM control组&#xff0c;子区控制参数 2) NOR/PSRAM timi…...

【3】安装cyclictest和iperf

cyclictest 安装比较简单&#xff0c;我是直接使用命令行&#xff1a; apt-get install rt-tests 随后&#xff0c;运行 sudo cyclictest 但是这个程序会一直运行&#xff0c;直到你手动中断程序&#xff0c;而且每秒生成一行输出也很烦人&#xff0c;所以可以选择把结果…...

C语言将点分十进制的IP字符串转成4个整数

最近在做lldp的snmp返回值时需要做这样的转换处理&#xff1a;C语言将点分十进制的IP字符串转成4个整数。 这里用两种方式&#xff1a; sscanf格式化处理用 inet_aton函数将ip字符串转成32位的整形&#xff0c;然后再根据bit转成对应的4个整数。 man命令可以确认下sscanf和i…...

go语言学习 笔记 1(变量,语法,数据类型)

1,包管理 一个文件夹可以称为一个包 在一个包里面可以创建多个文件 包中可以创建包 同一个包内的同一级的包的名字要相同 如:包a中的包b.包b中的包得是同一个package,a中和包b同级的包名字也得是一个名字 必须要有一个main包,入口,就像是c必须有一个main函数 如果没有mai…...

无网络时自动切换备用网络环境

目录 背景目标为什么需要做自动网络切换网络切换手段 网络环境实现思路和代码部署脚本开机自动执行附录连接两个网络时的路由问题 背景 目标 学校实验室有两个网络环境&#xff0c;我电脑使用网线连接稳定但低速的网络A&#xff0c;使用WiFi连接高速但不稳定的网络B。因此&am…...

电脑32位和64位之区别(Difference between 32-Bit and 64 Bit Computers)

电脑32位和64位之区别 很多小伙伴还不知道电脑32位和64位是什么意思&#xff0c;今天小编就来普及一下。 32位和64位是指电脑处理器&#xff08;CPU&#xff09;和操作系统的架构&#xff0c;决定了电脑如何处理数据、存储信息、运行程序等。 32位和64位是指电脑系统中每个处…...

系统思考—结构影响行为

前段时间&#xff0c;我遇到了一位健康食品初创公司的创始人&#xff0c;产品质量毋庸置疑&#xff0c;但销量却始终打不开局面&#xff0c;资金链也日渐紧绷。他一脸困惑地问我&#xff1a;“我们已经尽力了&#xff0c;为什么结果还是不如人意&#xff1f;”经过深入交流&…...

【算法不挂科】算法期末考试【选择题专项练习】<多单元汇总>

前言 大家好吖&#xff0c;欢迎来到 YY 滴算法不挂科系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 下面是相关传送门 【算法不挂科】算法期末考试题库1&#xff08;带解析&#xff09;【选择题53道&#xff06;填空题36道&#xff06;算法填空题7道&a…...

2025.1.8(c++对c语言的扩充——堆区空间,引用,函数)

笔记 上一笔记接续&#xff08;练习2的答案&#xff09; 练习&#xff1a;要求在堆区连续申请5个int的大小空间用于存储5名学生的成绩&#xff0c;分别完成空间的申请、成绩的录入、升序排序、成绩输出函数以及空间释放函数&#xff0c;并在主程序中完成测试 要求使用new和d…...

如何将Yum源修改为本地挂载的ISO镜像

要将yum源修改为本地挂载的ISO镜像,您可以按照以下步骤进行操作。假设您使用的是CentOS或类似的基于Red Hat的Linux发行版,且已经将ISO镜像文件挂载到系统中。 步骤一:挂载ISO镜像 创建一个挂载点: 首先,您需要创建一个目录来作为ISO镜像的挂载点。例如: sudo mkdir /mnt…...

salesforce如何在系统里保存密码

在 Salesforce 中&#xff0c;保存密码或类似敏感信息时&#xff0c;不应以明文形式存储&#xff0c;而应采用安全的加密和存储机制。以下是一些最佳实践和实现方法&#xff1a; 1. 使用 Salesforce 提供的加密机制 Salesforce 提供了一些内置的加密工具&#xff0c;可以用来加…...

函数提升+上下文+内存清理及释放

文章目录 函数提升上下文函数释放拓展-垃圾回收机制垃圾回收之触发应用 函数提升上下文 函数提升&#xff08;Hoisting&#xff09; 概念&#xff1a;在JavaScript中&#xff0c;函数声明会被提升到当前作用域的顶部。这意味着可以在函数声明之前调用函数。例如&#xff1a; sa…...

计算机网络之---计算机网络的性能评估

计算机网络的性能评估是指通过各种标准和指标来衡量网络的工作效率和质量&#xff0c;进而对网络进行优化和改进的过程。评估的目标是确保网络能够满足预期的服务质量&#xff08;QoS&#xff09;和性能需求。常见的计算机网络性能评估指标包括带宽、延迟、吞吐量、丢包率等。 …...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...