C++通用编程(2)

news2024/11/19 13:38:38

函数模板高级用法

  • 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去修改列表内容效果是完全一样的。 ↩︎

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

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

相关文章

C# winform 多语言(json)方式实现

前后对比 使用nuget json工具包1.总体思路 创建对应的json字典对照表 { "测试":"Test", "语言":"Language", "设置":"Set", "中文(默认)":"Chinese (default)", "英文":"E…

【对象属性拷贝】⭐️按照需要转换的类型反射设置拷贝后对象的属性

背景&#xff1a; 小伙伴们大家好&#xff0c;最近开发的时候遇到一种情况&#xff0c;项目引入了全局序列化器来实现Date&#xff0c;LocalDateTime类型的字段根据时区转换&#xff0c;总体来说接口没什么要改动的&#xff0c;只要原来字段的属性是以上两种就行&#xff0c;但…

【linux】校招中的“熟悉linux操作系统”一般是指达到什么程度?

这样&#xff0c;你先在网上找一套完整openssh升级方案&#xff08;不是yum或apt的&#xff0c;要源码安装的&#xff09;&#xff0c;然后在虚拟机上反复安装测试&#xff0c;直到把他理解了、背下来。 面试的时候让你简单说说linux命令什么的&#xff0c;你就直接把这个方案…

Linux服务详解

如有错误或有补充&#xff0c;以及任何改进的意见&#xff0c;请在评论区留下您的高见&#xff0c;同时文中给出大部分命令的示例&#xff0c;即是您暂时无法在Linux中查看&#xff0c;您也可以知道各种操作的功能以及输出 如果觉得本文写的不错&#xff0c;不妨点个赞&#x…

CentOS 7中搭建NFS文件共享服务器的完整步骤

CentOS 7中搭建NFS文件共享服务器的完整步骤 要求&#xff1a;实现镜像文件共享&#xff0c;并基于挂载的共享目录配置yum源。 系统环境&#xff1a; 服务器&#xff1a;172.20.26.167-CentOS7.6 客户端&#xff1a;172.20.26.198-CentOS7.6 1、在服务器和客户端上&#x…

案例分析技巧-软件工程

一、考试情况 需求分析&#xff08;※※※※&#xff09;面向对象设计&#xff08;※※&#xff09; 二、结构化需求分析 数据流图 数据流图的平衡原则 数据流图的答题技巧 利用数据平衡原则&#xff0c;比如顶层图的输入输出应与0层图一致补充实体 人物角色&#xff1a;客户、…

MySQL 索引和事务

目录 1 索引1.1 简介1.2 使用1.3 示例 2 事务2.1 简介2.2 使用 1 索引 1.1 简介 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引&#xff0c;并指定索引的类型&#xff0c;各类索引有各自的数据结构实现。 索引底层是…

TypeScript 学习笔记(Day4)

「写在前面」 本文为 b 站黑马程序员 TypeScript 教程的学习笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。推荐先按顺序阅读往期内容&#xff1a; 1. TypeScript 学习笔记&#xff08;Day1&#xff09; 2. TypeScript 学习笔…

Three.js学习2:页面引入 Three.js

一、关于 Three.js 的版本 随着页面3D化应用越来越多&#xff0c;近两年 Three.js 处于飞速发展之中。现在 Three.js 几乎每个月都会发布一个新的版本&#xff0c;会增加新的 API&#xff0c;废掉一些旧的功能之类的。 可以从 Three.js 官网 Three.js – JavaScript 3D Libra…

web漏洞扫码工具

Invicti 是一种自动化但完全可配置的 Web 应用程序安全扫描程序&#xff0c;使您能够扫描网站、Web 应用程序和 Web 服务&#xff0c;并识别安全漏洞。Invicti 可以扫描所有类型的 Web 应用程序&#xff0c;无论其构建平台或语言。 Invicti 是唯一一款能够以只读且安全的方式自…

Next.js初识

Next.js初识 Next.js&#xff1a;这是一个用于生产环境的React 框架&#xff08;国外用的比较多&#xff09;。 Next.js 为您提供生产环境所需的所有功能以及最佳的开发体验&#xff1a;包括静态及服务器端融合渲染、 支持 TypeScript、智能化打包、 路由预取等功能 无需任何配…

c#的反汇编对抗

文章目录 前记nim攻防基础FFI内存加载加解密、编码 后记C#类型转换表nim基础 前记 随便编写一个c#调用winapi并用vs生成dll,同时用csc生成exe using System; using System.Runtime.InteropServices; namespace coleak {class winfun{[DllImport("User32.dll")]publ…

【JavaEE进阶】 图书管理系统开发日记——叁

&#x1f334;前言 在前面我们实现了用户登录的接口。现在我们来实现图书列表展示页面。 &#x1f38b;数据准备 创建图书表&#xff0c;并初始化数据 -- 图书表 DROP TABLE IF EXISTS book_info; CREATE TABLE book_info (id INT ( 11 ) NOT NULL AUTO_INCREMENT,book_nam…

【数据开发】pyspark入门与RDD编程

【数据开发】pyspark入门与RDD编程 文章目录 1、pyspark介绍2、RDD与基础概念3、RDD编程3.1 Transformation/Action3.2 数据开发流程与环节 1、pyspark介绍 pyspark的用途 机器学习专有的数据分析。数据科学使用Python和支持性库的大数据。 spark与pyspark的关系 spark是一…

CMake Msys2 搭配vscode

(一)MSYS2介绍 MSYS2&#xff08;Minimal SYStem 2&#xff09;是一个集成了大量的GNU工具链、工具和库的开源软件包集合。它提供了一个类似于Linux的shell环境&#xff0c;可以在Windows系统中编译和运行许多Linux应用程序和工具。 MSYS2基于MinGW-w64平台&#xff0c;提供了…

分布式事务 seata+nacos 部署

分布式事务 seatanacos 部署 一、下载seata二、解压配置三、导入数据库四、nacos配置五、配置要引入事务的模块的配置文件六、启动七、测试 这里使用的版本&#xff1a; nacos&#xff1a;2.0.4 seata&#xff1a;1.5.2 seata官方地址&#xff1a;https://seata.apache.org/zh-…

unity addressables 加载资源和场景 显示进度条(主要用于WebGL)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、addressables是什么&#xff1f;二、导入Addressables三、创建Addressables Settings 资产包管理四、资源打包五、环境模拟六、查看重复资源七、选择Bundle…

WordPress主题YIA的文章页评论内容为什么没有显示出来?

有些WordPress站长使用YIA主题后&#xff0c;在YIA主题设置的“基本”中没有开启“一键关闭评论功能”&#xff0c;而且文章也是允许评论的&#xff0c;但是评论框却不显示&#xff0c;最关键的是文章原本就有的评论内容也不显示&#xff0c;这是为什么呢&#xff1f; 根据YIA主…

【毕业日记】2024.01 - 慢下来,静待花开

转眼距离930离开鹅厂已经120天了&#xff0c;我是很能拖延的&#xff0c;或者是很懂自我麻痹的&#xff0c;这三个多月&#xff0c;一直想要写点东西纪念&#xff0c;一直拖一直拖一直拖…… 疫情这几年经济下行里裁员是个茶余饭后“嬉笑”之余经常被提起的词&#xff0c;部门滚…

python 实现 macOS状态栏 网速实时显示

安装依赖包&#xff1a; pip install pillow psutil rumpsnetSpeedApp.py from PIL import Image, ImageDraw, ImageFont import psutil import rumpsclass NetSpeedApp(rumps.App):def __init__(self):super(NetSpeedApp, self).__init__("NetSpeed")self.titlese…