C++函数模板

简介:C++函数模板的作用就是按照程序员的要求生成想要的函数对象。本质上是一种函数声明,在程序运行时依靠指定的参数类型由编译器临时生成函数对象。

1、auto自动类型推导

        auto关键字可以取代变量声明时的函数类型,其实实际上会由编译器帮你把auto换成匹配的数据类型。

#include<iostream>
using namespace std;int* get_a_arr(){int* arr= new int(10);return arr;
}int main(){auto a=3;auto b=3.14;auto arr = get_a_arr();cout<<"值是:"<<a<<endl<<"类型是:"<<sizeof(a)<<endl;
}

        auto的注意点:

  1. auto关键字修饰的变量的右值必须是类型确定的表达式(需要根据表达式进行类型推断)
  2. auto关键字修饰的变量必须初始化(不声明的话不知道类型)
  3. auto不能修饰函数的形参变量(会出现推断二义性)
  4. auto不能直接修饰数组变量(会出现推断二义性)
  5. auto不能修饰静态变量(会出现推断二义性)

        auto的正确用法:

  1. 用于自动推导复杂的数据类型(例如自动推导函数指针类型)
  2. 用于自动推导函数返回类型
#include<iostream>
using namespace std;int* get_a_arr(){int* arr= new int[10];for(int i=0;i<=10;i++)*(arr+i)=i;return arr;
}int main(){auto pf=get_a_arr;int* arr = pf();for(int i=0;i<=10;i++)cout<<*(arr+i)<<endl;
}

2、函数模板

        函数模板将函数所用到的数据类型参数化,形成一个函数声明。可以自定义类型的数据:函数形参的数据类型、函数返回值的数据类型、栈区里面由函数临时生成的数据类型。

        具体的函数对象由传递过来的具体数据类型进行确定之后再生成。传递的给模板的数据类型可以手动指定也可以由编译器自动推导(根据auto推导)。由此会产生下面的问题:

  1. 这个由函数模板生成的函数对象很有可能与普通函数对象长得一样,此时编译器会优先调用普通函数。
  2. 函数模板会生成多个同名函数,那么这些函数由于参数类型不同、个数不同,从而构成函数重载。
  3. 当模板和普通函数优先级一样时,可能需要强制调用模板函数;
  4. 生成函数对象之前,需要明确地知道参数的类型

        函数模板的语法形式如下:template<typename anytype1,typename anytype2,……>

#include<iostream>
using namespace std;template <typename T>
void swap(const T &var1,const T &var2){T temp = var1;var2=var1;var1=temp;
}int main(){int i1=1,i2=2;swap(i1,i2);//编译器自动推导类型cout<<i1<<";"<<i2<<endl;float f1=1.1,f2=2.2;swap<float>(f1,f2);//手动指定数据类型cout<<f1<<";"<<f2<<endl;}

3、函数模板的注意事项

3.1 类成员函数可以加上模板

        本质就是将普通函数放到类里面。构造函数、成员方法都可以改成模板函数使用,原因就是类就是一个结构体,存在一个函数指针引用着生成的函数对象,这个函数对象可以临时生成。

#include<iostream>
using namespace std;class Cgirl {public:template <typename T>Cgirl(T info) {cout << info << endl;}Cgirl() {}template <typename T>void showinfo(T info) {cout << info << endl;}};int main() {Cgirl c;c.showinfo(18);c.showinfo("mmd");}

3.2 需要明确模板形参类型

        不管是自动类型推导,还是手动指定类型,都需要将模板声明中的类型进行赋值,这样才能没有二义性的生成一个函数对象。

        情况2:

3.3 函数模板的代码逻辑必须满足传递的数据类型

        如果给函数传递的是自定义数据类型,也就是类型对象,那么函数的代码逻辑运算必须满足该自定义数据类型。

3.4 模板函数的自动数据类型转换

        由于类型可以自动auto推导也可以手动指定,然而自动推导存在二义性,比如一个字符串可以是char*类型,也可以时string类型,故所有自动推导的函数模板不存在类型自动转换。比如char向int再向float的转换。

        但是手动指定模板类型之后,就可以发生自动类型转换。

3.5 模板类型和具体数据类型混用构造重载

        模板类型之间是互异的,就构成了参数类型不一致,也就是可以构成重载。

#include<iostream>
using namespace std;template <typename T, typename T2>
void showinfo(T info1, T2 info2) {cout << info1 << endl;cout << info2 << endl;
}template <typename T>
void showinfo(T info1) {cout << info1 << endl;
}template <typename T>
void showinfo(T info1, char* info2) {cout << info1 << endl;cout << info2 << endl;
}int main() {showinfo(10, 12.0);showinfo(10);showinfo(10, "mmd");
}

4、函数模板的具名化

        由于自定义数据类型的存在,对对象的操作就比较特殊,可以在声明模板时指定数据类型,使其变得普通函数类似。

#include<iostream>
using namespace std;class Cgirl {public:int rank;
};template <typename T>
void Swap(T &p1, T &p2) {T temp = p1;p1 = p2;p2 = temp;
}template<>
void Swap<Cgirl>(Cgirl &p1, Cgirl &p2) {int temp = p1.rank;p1.rank = p2.rank;p2.rank = temp;
}int main() {Cgirl p1;p1.rank = 1;Cgirl p2;p2.rank = 2;cout << p1.rank << "--" << p2.rank<<endl;swap(p1,p2);cout << p1.rank << "--" << p2.rank;
};

        当普通函数、模板函数、具体化模板函数都可以匹配某个函数调用时,优先级为普通函数-->具体化函数-->模板函数。

5、函数模板的分文件编写

        目前存在:普通函数、具体化模板函数、模板函数。实际上,普通函数、具体化模板函数是等价的,也就是具体化模板函数就可以看作是普通函数。

        那么在头文件当中具体化模板函数和普通函数只能写上声明,具体实现需要在源文件里面书写。

        模板函数只是一种声明,他的整段代码都只能写在头文件里面当中一个函数声明。

6、模板函数里面的类型转换

        一个函数模板可能会存在多个数据类型参数,当这些数据发生运算时就会生成新的数据类型,如何自动推断这些数据的类型呢?如果需要返回这个新的数据类型数据又该如何操作呢?可以使用decltype自动推导类型。

        语法:decltype(expression) var。decltype(expression)的推导结果就是var的数据类型。

  • 如果expression是没有用括号括起来的标识符,则var的类型与该标识符的类型相同,包括const等限定符。
#include<iostream>
using namespace std;int main() {
//语法:decltype(expression) var;
//1)如果expression是没有用括号括起来的标识符,则var的类型与该标识符的类型相同,包括const等限定符,
int a=1;
int b=2;
int &ra=a;
decltype(ra) da=b;
cout<<da;
};
  • 如果expression是函数调用,则var的类型与函数的返回值类型相同(函数不能返回void,但可以返回void*)。
  • 如果expression是左值(能取地址)、或者用括号括起来的标识符,那么var的类型是expression的引用。
  • 如果上面的条件都不满足,则var的类型与expression的类型相同。

        总结:var要么是引用,要么时expression的类型。而且函数返回类型可以直接使用auto进行推断。

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

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

相关文章

智能私信神器,转化率飙升的秘密!

在当今信息爆炸的时代&#xff0c;企业和商家面临着巨大的竞争压力&#xff0c;如何有效地吸引潜在客户、提高客户转化率成为摆在每一位市场营销人员面前的难题。随着人工智能技术的不断发展&#xff0c;智能私信软件应运而生&#xff0c;为企业提供了一个高效、便捷的解决方案…

前端发起网络请求的几种常见方式(XMLHttpRequest、FetchApi、jQueryAjax、Axios)

摘要 前端发起网络请求的几种常见方式包括&#xff1a; XMLHttpRequest (XHR)&#xff1a; 这是最传统和最常见的方式之一。它允许客户端与服务器进行异步通信。XHR API 提供了一个在后台发送 HTTP 请求和接收响应的机制&#xff0c;使得页面能够在不刷新的情况下更新部分内容…

HSDB使用教程

HSDB&#xff1a;Hostspot Debugger&#xff0c;JVM内置的工具&#xff0c;用于深入分析JVM运行时的内部状态 启动HSDB java -cp D:/tools/jdk-1.8/lib/sa-jdi.jar sun.jvm.hotspot.HSDB 获取进程id jps 连接到指定进程 查找类 通过查询查找对象 输入查询语句 select d from …

扫雷实现详解【递归展开+首次必展开+标记雷+取消标记雷】

扫雷 一.扫雷设计思路二.扫雷代码逐步实现1.创建游戏菜单2.初始化棋盘3.打印棋盘4.随机布置雷5.统计周围雷的个数6.递归展开棋盘7.标记雷8.删除雷的标记9.保证第一次排雷的安全性棋盘必定展开10.排查雷11.判断输赢 三.扫雷总代码四.截图 一.扫雷设计思路 1.创建游戏菜单。  2.…

Vue入门到关门之Vue项目工程化

一、创建Vue项目 1、安装node环境 官网下载&#xff0c;无脑下一步&#xff0c;注意别放c盘就行 Node.js — Run JavaScript Everywhere (nodejs.org) 需要两个命令 npm---->pipnode—>python 装完检查一下&#xff0c;hello world检测&#xff0c;退出crtlc 2、搭建vu…

SwiftUI 5.0(iOS 17.0,macOS 14.0+)新 Inspector 辅助视图之趣味漫谈

概览 在 SwiftUI 开发中,苹果为我们提供了多种辅助视图用来显示额外信息从而极大丰富了应用的表现力,比如:Alert、Sheet、ContextMenu 等等。 从 SwiftUI 5.0(iOS 17+)开始, 又增加了一种全新的辅助视图:Inspector。 在本篇博文中,您将学到如下内容: 概览1. Inspe…

LangChain入门:24.通过Baby AGI实现自动生成和执行任务

随着 ChatGPT 的崭露头角,我们迎来了一种新型的代理——Autonomous Agents(自治代理或自主代理)。 这些代理的设计初衷就是能够独立地执行任务,并持续地追求长期目标。 在 LangChain 的代理、工具和记忆这些组件的支持下,它们能够在无需外部干预的情况下自主运行,这在真…

1-手工sql注入(基础篇)

关于靶场: 本章使用的靶场是pikachu和dvwa&#xff1a;针对于pikachu靶场上的sql注入pikachu和dvwa靶场下载地址&#xff1a;GitHub - digininja/DVWA: Damn Vulnerable Web Application (DVWA)GitHub - zhuifengshaonianhanlu/pikachu: 一个好玩的Web安全-漏洞测试平台 一. sq…

QT中基于TCP的网络通信

QT中基于TCP的网络通信 QTcpServer公共成员函数信号 QTcpSocket公共成员函数信号 通信流程服务器端通信流程代码 客户端通信流程代码 多线程网络通信SendFileClientSendFileServer 使用Qt提供的类进行基于TCP的套接字通信需要用到两个类&#xff1a; QTcpServer&#xff1a;服…

yolo系列目标分类模型训练结果查看

常用指标&#xff1a; 准确率&#xff08;Accuracy&#xff09; Accuracy (TP TN) / (TP TN FP FN) 正确预测的样本数占总样本数的比例。精确率&#xff08;Precision&#xff09; Precision TP / (TP FP) 在所有预测为正的样本中&#xff0c;真正的正样本所占的比例。召…

安装vscode基础配置,es6基础语法,

https://code.visualstudio.com/ es6 定义变量 const声明常量&#xff08;只读变量&#xff09; // 1、声明之后不允许改变 const PI “3.1415926” PI 3 // TypeError: Assignment to constant variable. // 2、一但声明必须初始化&#xff0c;否则会报错 const MY_AGE /…

Word文件后缀

Word文件后缀 .docx文件为Microsoft Word文档后缀名&#xff0c;基于XML文件格式 .dotm为Word启用了宏的模板 .dotx为Word模板 .doc为Word97-2003文档&#xff0c;二进制文件格式 参考链接 Word、Excel 和 PowerPoint 的文件格式参考 Learn Microsoft

专项技能训练五《云计算网络技术与应用》实训7-1:安装mininet

文章目录 mininet安装1. 按6-1教程安装opendaylight控制器。2. 按6-2教程安装RYU控制器。3. 按5-1教程安装openvswitch虚拟交换机并开启服务。4. 将老师所给mininet安装包试用winSCP传送至电脑端。5. 安装net-tools。6. 安装mininet7. 安装完成后&#xff0c;使用命令建立拓扑&…

基于Springboot的旅游管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的旅游管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

服务网关GateWay原理

文章目录 自动装配核心类GatewayAutoConfigurationDispatcherHandler请求处理阶段apply方法httpHandler#handle方法WebHandler#handle方法DispatchHanlder#handle方法第一步 getHandler获取请求映射第二步 invokeHandler 请求适配第三步 handleResult请求处理总结 上一篇博文我…

【机器学习原理】决策树从原理到实践

基于树的模型是机器学习中非常重要的一类模型&#xff0c;最基础的就是决策树&#xff0c;本篇主要讲述决策树的原理和几类最常见的决策树算法&#xff0c;这也是更复杂的树模型算法的基础。 参考文章&#xff1a; 1.CSDN-基于熵的两个模型(ID3,C4.5)比较详细&#xff0c;有数字…

富文本编辑器 iOS

https://gitee.com/klkxxy/WGEditor-mobile#wgeditor-mobile 采用iOS系统浏览器做的一款富文本编辑器工具。 原理就是使用WKWebView加载一个本地的一个html文件&#xff0c;从而达到编辑器功能的效果&#xff01; 由于浏览器的一些特性等&#xff0c;富文本编辑器手机端很难做…

零基础学习数据库SQL语句之查询表中数据的DQL语句

是用来查询数据库表的记录的语句 在SQL语句中占有90%以上 也是最为复杂的操作 最为繁琐的操作 DQL语句很重要很重要 初始化数据库和表 USE dduo;create table tb_emp(id int unsigned primary key auto_increment comment ID,username varchar(20) not null unique comment…

打工人必备的定时自动化神器

作为打工人&#xff0c;时间管理是一个很重要的观念。面对繁杂的事务&#xff0c;往往会造成某些事情忘记的情况 今天苏音看到一款自动化的任务神器&#xff0c;据说可以实现一键自动定时&#xff0c;并且还支持语音报时和定时任务执行 让我们一起来看看吧。 软件名字——ZT…

【leetcode】数组和相关题目总结

1. 两数之和 直接利用hashmap存储值和对于索引&#xff0c;利用target-nums[i]去哈希表里找对应数值。返回下标。 class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {unordered_map<int, int> mp;vector<int> res;fo…