C++通用编程(2)

函数模板高级用法

  • 1.分文件编写的优点
  • 2.普通函数的分文件编写
  • 3.函数模板的分文件编写
  • 4.细节提示
  • 5.函数模板应用高级
    • decltype推导类型
    • 函数后置返回类型
  • 6.总结

函数模板讲完后,C++全部的函数类型我们就接触的差不多了。今天给做一些关于函数份文件编写的知识点补充。

1.分文件编写的优点

在以往的学习中,我们将函数全部放在一个.cpp文件中,随着任务量的变化,我们的代码越写越多,功能也越写越乱。如果这是在实际生产中,后面需要维护代码也会变得非常困难。如果我们可以把所有的函数和功能分门别类,既方便根据需求找到函数,又能让主函数代码量减少很多,维护起来也就方便的多了。
那么如何实现这个功能呢?
(PS:本节内容以Visual Studio软件进行演示,如果大家用的是VScode,可以参考下节内容)

2.普通函数的分文件编写

对于普通函数而言,我们只需要在任务目录下创建一个.h后缀的头文件和一个同名的.cpp后缀的源文件,将函数声明和文件的引用放在头文件里,将函数的定义放在源文件里就可以了:
在这里插入图片描述如果大家是在主界面新建的C++空项目,右边栏会这样显示:
在这里插入图片描述
我们在"头文件"中创建.h,在"源文件"中创建同名的.cpp即可。
然后再回到主函数(2.cpp)中引用头文件,就可以实现函数分文件了:
在这里插入图片描述

3.函数模板的分文件编写

文件模板是一个函数的描述,没有实体,如果我们还按普通函数的处理方式分文件编写,2.cpp文件将不能正常运行(大家可以自行尝试)。应当将函数通用模板整个放到头文件中避免这个问题,但是当函数模板存在具体化时,函数模板的具体化又应当与普通函数的处理方式相同:
在这里插入图片描述
运行2.cpp的结果为:
在这里插入图片描述

因为具体函数是不允许有通用类型参数的,所以具体函数和普通函数处理方法相同也就不足为奇了。

4.细节提示

1.在public.h文件中已经引用的内容,主函数引用了public.h的情况下就没必要再次引用
2.引用public.h可以使用绝对路径,即

# include"C:/c++/project1/public.h"

同理,使用这样的方式也可以引用其他位置的自定义头文件

5.函数模板应用高级

decltype推导类型

在之前的讲述中,我们已经知道了除了参数的类型以外,任何编写代码的过程中遇到的不确定类型的变量都可以使用auto去声明。但是这里我们给大家介绍另一种确定类型的方法:decltype。其语法如下

decltype(expression) var

意思是推导出表达式的类型并定义一个同类型变量var,且表达式的内容不会被执行。其规则为:
1.当表达式是一个标识符且不带括号时,var与表达式内容同类型:

    int a=10;
    decltype(a) var;

我们可以把鼠标移动到var上查看推导出来的类型:
在这里插入图片描述

2.如果表达式是函数(或其他什么)的调用,则var的类型与返回值相同(返回值不能是void类型否则会报错):

void* function() // 这里仅为证明void*类型作为返回值的函数可以作为decltype中的表达式。
				 // 但是没有return不正规,大家还是要规范编程
{
    cout<<"这里是function函数"<<endl;
}
int main()
{
    int a=10;
    decltype(function()) var;
}
// 输出为:

运行文件终端什么都没有,这说明function函数没有被调用。
这个功能实现方式与auto就有所区别了,如果我们使用auto去定义函数指针:

auto *var=function();

var会被定义成指向function的函数指针,但是函数会被调用。当然auto也可以仅依靠函数名推理出类型:

int main()
{
    auto var=function;
}

这样var就成了指向function的函数指针了,运行这段代码函数也不会被调用。
3.如果表达式是一个函数名或带有赋值性质的语句1或括号括起来的变量,var的类型是表达式的引用:

int main()
{
    int a=10,b;
    decltype(function) var;
    decltype((a)) var2=a;
    // decltype(a=1+3) var2=b;
}

这段代码中,var就是void* ()类型,var2是int类型的引用类型(这里不懂的小伙伴先往下看)。如果我们把var前面加上*,就是声明了一个函数指针var:

decltype(function) *var;
var=function;
var();
// 输出为:这里是function函数

引用就是联动多个变量,有点像python的列表2。观察下面代码,如果我们修改var2,那么var2联动变量的值也会随之修改:

int main()
{
    int a=10,b=20;
    decltype(++a) var2=b; // 因为++a实际上是表达式a=a+1,含有赋值语句,
    					  // 因此这里的b是a(赋值语句的左值)类型引用的类型
    // decltype(a=1+3) var2=b;
    var2=30;
    cout<<b<<" "<<a<<endl;
}
// 输出为:30 10

多数情况下,decltype声明的变量没必要直接定义,但如果推理出的类型是引用类型就必须在声明时定义了。事实上,即使我们用确定的类型名定义引用类型也需要在声明时定义才能通过编译:

int a=10;
int &ra=a;

4.如果上面情况都不符合,decltype推到结果是表达式类型:

int main()
{
    int x=10,y=20;
    decltype(3) var;
    decltype(x+y) var2;
    decltype(3+1) var3;
}

这里var、var2、var3都被推导为int类型。

函数后置返回类型

这里的内容在C++14标准后就没有学习的意义了,不感兴趣的小伙伴可以直接看最后的例子。
如果我们写的函数不知道返回值具体类型,该怎么办呢?C++允许在定义(和声明)函数后规定返回值数据类型,其示例如下:

int fun(int a,int b)->int

这个看起来没什么用,但如果不知道具体返回值类型就可以用到了:

template <typename T>
auto fun(T a,T b)->decltype(a+b)

这样就利用自动推导解决了返回值类型的问题了。然而之前我们解决这个问题是直接定义返回值类型为auto,看起来没必要这么麻烦。这是因为C++14标准对函数返回类型推导规则做了优化。下面我们再来规范的写一个可以实现交换两个变量并返回两变量和功能的函数模板:

template <typename T>
auto SWAP(T &a,T &b)->decltype(a+b) // 这样的判断结果不是引用类型
// 等同于 auto fun(T a,T b) 写法
{
	decltype(a+b) tmp=a; // 亦可写作auto temp = a
					     // 但这样写更保险
    a=b;
	b=tmp;
	return a+b;
}
int main()
{
    string a="San",b="Zhang";
    cout<<SWAP(a,b)<<"\n"<<a<<"\n"<<b<<endl;
}
// 输出为:ZhangSan
// 		  Zhang
//		  San

6.总结

这节内容总算是告一段落了,我们重点讲解的是函数分文件编写和decltype标识推导未知类型。decltype方法虽然比auto复杂很多,但能实现的功能以及安全性上也有更好的表现效果,这两种方式可以说是各有千秋。后续我们一起继续学习类模板~


  1. 当表达式为带有赋值性质语句时,推断依赖于这个表达式左值的类型 ↩︎

  2. 在Python中,假有列表a=[1,2,3,4],后续有语句b=a,那么这句话就会被解读为b和a同时代表这个列表,而不是b单独复制了一份a的内容。通过b去修改列表内容和通过a去修改列表内容效果是完全一样的。 ↩︎

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

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

相关文章

C语言问题汇总

指针 #include <stdio.h>int main(void){int a[4] {1,2,3,4};int *p &a1;int *p1 a1;printf("%#x,%#x",p[-1],*p1);} 以上代码中存在错误。 int *p &a1; 错误1&#xff1a;取a数组的地址&#xff0c;然后1&#xff0c;即指针跳过int [4]大小的字节…

调试以及发布npm组件

开发原因&#xff1a; 由于公司自己的封装到npm的组件有点问题&#xff0c;负责人由在忙其他&#xff0c;就由我去负责改改&#xff0c;中途出了不少问题&#xff0c;记录一下。 一、下载源码 第一步肯定是去git上把组件的源码下载下来&#xff0c;这一步没什么好说&#xf…

日志记录——单片机可执行文件合并

一&#xff1a;需求场景 现在有一片单片机&#xff0c;执行程序包括自定义boot和应用程序app, 在将打包好的固件给到生产是有以下问题&#xff0c;由于要通过jlink烧录boot&#xff0c;然后上电启动boot&#xff0c;通过boot烧录初始化程序&#xff0c;过程过于复杂&#xff0…

Oracle和Mysql数据库

数据库 Oracle 体系结构与基本概念体系结构基本概念表空间(users)和数据文件段、区、块Oracle数据库的基本元素 Oracle数据库启动和关闭Oracle数据库启动Oracle数据库关闭 Sqlplussqlplus 登录数据库管理系统使用sqlplus登录Oracle数据库远程登录解锁用户修改用户密码查看当前语…

嵌入式软件中常见的 8 种数据结构

数据结构是一种特殊的组织和存储数据的方式&#xff0c;可以使我们可以更高效地对存储的数据执行操作。数据结构在计算机科学和软件工程领域具有广泛而多样的用途。 几乎所有已开发的程序或软件系统都使用数据结构。此外&#xff0c;数据结构属于计算机科学和软件工程的基础。当…

SpringBoot:@Profile注解和Spring EL

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 前言一、Prof…

业务流程自动化平台在制造业应用案例,助力业务自动化、智能化

捷昌驱动成立于2000年&#xff0c;并于2018年9月在上海证券交易所上市&#xff0c;是一家专注于线性驱动产品研发、生产及销售的科技集团。 公司整合全球资源&#xff0c;为智慧办公、医疗康护、智能家居、工业自动化等关联产业提供驱动及智能控制解决方案&#xff0c;以科技驱…

Linux系统安全:安全技术 和 防火墙

一、安全技术 入侵检测系统&#xff08;Intrusion Detection Systems&#xff09;&#xff1a;特点是不阻断任何网络访问&#xff0c;量化、定位来自内外网络的威胁情况&#xff0c;主要以提供报警和事后监督为主&#xff0c;提供有针对性的指导措施和安全决策依据,类 似于监控…

Sentinel安装

1、下载 sentinel官方提供了UI控制台&#xff0c;方便我们对系统做限流设置。大家可以在GitHub下载。 2、运行 将jar包放到任意非中文目录&#xff0c;执行命令&#xff1a; java -jar sentinel-dashboard-1.8.1.jar 如果要修改Sentinel的默认端口、账户、密码&#xff0c;…

【unity小技巧】unity3d环境带雾的昼夜系统变化

最终效果 文章目录 最终效果眩光素材眩光配置全局灯光配置天空盒配置天空盒资产配置天空盒&#xff0c;开启雾 代码控制天空盒 环境 雾 灯光昼夜交替变化参考完结 眩光素材 链接&#xff1a;https://pan.baidu.com/s/1qlFSJSju6ZjwCylwkh14eA?pwdveww 提取码&#xff1a;veww…

面试150 二进制求和 位运算

Problem: 67. 二进制求和 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 参考 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( n ) O(n) O(n) Code class Solution {public String addBinary(String a, String b){StringBuilder ans new Stri…

【知识点】Java多线程

文章目录 线程基础happen-before规则基础概念线程方法线程状态转换状态控制参考链接 线程应用线程安全常用锁独享锁 VS 共享锁自旋锁可重入锁 VS 非可重入锁锁的状态无锁偏向锁轻量级锁重量级锁综述 公平锁非公平锁同步锁乐观锁悲观锁对比 AQS基础说明原理概览常用方法应用场景…

Java 基于 SpringBoot+Vue 的考研论坛管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

十分钟上手vue!

Vue 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。无论是简单还是复杂的界面&#xff0c;Vue 都可以胜任。 一 vue.js的导入及使用 vue安装…

【Boost】:parser代码的基本结构(二)

parser代码的基本结构 一.总体概述二. EumeFile的实现三.ParserHtml的实现四.SaveHtml实现五.完整源代码 打开parser.cc,用vscode或者vim都行。 一.总体概述 首先递归式的把文件名和路径读入一个数组内&#xff0c;接着把数组内的每一个数据按照一定的格式进行划分&#xff0c;…

云原生业务全流程DevOps配置预研与实践

背景 我在一个二线城市&#xff08;山东济南&#xff09;&#xff0c;相对与北上广深杭这些IT业发达的城市来说&#xff0c;济南IT业对于业内新技术的接受度是有点慢的&#xff0c;国内很多一线大厂早先几年前就开始实践使用的技术&#xff0c;我们这边也是近两年才开始慢慢兴…

10. BI - 决策树的使用及可视化

本文为 「茶桁的 AI 秘籍 - BI 篇 第 10 篇」 文章目录 可视化探索决策树原理决策树算法决策树可视化泰坦尼克海难数据 Hi&#xff0c;你好。我是茶桁。 上一节课&#xff0c;咱们了解了图形的具体绘制方法&#xff0c;接下来咱们还要看看除了图形绘制之外&#xff0c;还有哪些…

手把手教你开发Python桌面应用-PyQt6图书管理系统-主界面UI背景及状态栏代码设置

锋哥原创的PyQt6图书管理系统视频教程&#xff1a; PyQt6图书管理系统视频教程 Python桌面开发 Python入门级项目实战 (无废话版) 火爆连载更新中~_哔哩哔哩_bilibiliPyQt6图书管理系统视频教程 Python桌面开发 Python入门级项目实战 (无废话版) 火爆连载更新中~共计24条视频&…

山东淄博刑侦大队利用无人机抓获盗窃团伙

山东淄博刑侦大队利用无人机抓获盗窃团伙 近期&#xff0c;山东淄博临淄区发生多起盗窃案件。通过视频追踪和调查访问&#xff0c;推断临淄区某村可能为嫌疑人藏匿地点。刑侦大队无人机应急小组迅速到达现场&#xff0c;经无人机高空侦查&#xff0c;发现并锁定了嫌疑人的藏匿…

5. 基础网络服务与应用配置

5.1 实验一&#xff1a;FTP 基础配置实验 5.1.1 实验介绍 5.1.1.1 关于本实验 设备支持多种文件管理方式&#xff0c;用户根据任务和安全性要求选择合适的文件管理方式。 用户可以通过直接登录系统、FTP&#xff08;File Transfer Protocol&#xff09;、TFTP&#xff08;T…