[c++] 模板

news/2024/4/15 4:46:36/文章来源:https://blog.csdn.net/weixin_38184628/article/details/136533249

c++ 中的模板通过将类型参数化,可以提高代码的复用性。模板并不能减少代码量,只是从开发者的角度来看,代码量减少了,复用性提高了;从二进制文件的角度看,代码量没有减小。

1 函数模板

当求两个数的和时,数据的类型可能是 int、float 或者 double等,如果不使用模板的话,我们需要写下边的代码,每种数据类型都实现一个函数。这样当我们需要使用其它数据类型时,就需要再写一个函数。

#include <iostream>
#include <string>int sum(int a, int b) {std::cout << "int" << std::endl;return a + b;
}float sum(float a, float b) {std::cout << "float" << std::endl;return a + b;
}double sum(double a, double b) {std::cout << "double" << std::endl;return a + b;
}int main() {std::cout << sum(1, 2) << std::endl;std::cout << sum(1.1f, 2.2f) << std::endl;std::cout << sum(1.1, 2.2) << std::endl;return 0;
}

c++ 提供了模板,模板可以把类型参数化。针对上边的代码,在 c++ 中就可以使用模板函数来实现。代码如下所示,只需要定义一个模板函数就可以。

#include <iostream>
#include <string>template <class T>
T sum(T a, T b) {std::cout << "sum" << std::endl;return a + b;
}int main() {std::cout << sum(1, 2) << std::endl; // 隐式调用, 类型为 intstd::cout << sum(1.1f, 2.2f) << std::endl;  // 隐式转换,类型是 floatstd::cout << sum(1.1, 2.2) << std::endl; // 隐式转换,类型是 doublestd::cout << sum<int>(1, 2.2) << std::endl; // 显示转换,类型是 int, 如果不显式指定类型,编译器会出现二义性,到底是 int 还是 doublereturn 0;
}

模板函数的代码量减少了,但是编译之后的二进制文件并没有减少。使用 objdump -tT a.out 可以看到,其中生成了 3 个函数实例。将程序员的工作转化成了编译器的工作,如果是不使用模板,就需要开发者自己写那么多函数;使用模板的方式来定义函数,编译器会生成这些函数。

2 类模板

如下代码, Point_T 是一个模板类,表示一个点,其中包括点的横纵坐标 x 和 y,类型分别是 T1 和 T2。

#include <iostream>template <class T1, class T2>
class Point_T {
public:T1 x_;T2 y_;Point_T() : x_(0), y_(0) {std::cout << "default constructor" << std::endl;}Point_T(T1 x, T2 y) : x_(x), y_(y) {std::cout << "constructor" << std::endl;}Point_T<T1, T2>& operator=(const Point_T<T1, T2> &point) {this->x_ = point.x_;this->y_ = point.y_;return *this;}// +运算符重载,需要声明为 friendfriend Point_T<T1, T2> operator +(Point_T<T1, T2> &point1, Point_T<T1, T2> &point2) {Point_T<T1, T2> tmp;tmp.x_ = point1.x_ + point2.x_;tmp.y_ = point1.y_ + point2.y_;return tmp;}// << 运算符重载,需要声明为 friendfriend std::ostream& operator<< (std::ostream &out, const Point_T<T1, T2>& point) {out << "(" << point.x_ << ", " << point.y_ << ")" << std::endl;return out;};
};int main() {Point_T<int, int> int_point1(1, 2);Point_T<int, int> int_point2(10, 20);// 看到一些书上说了类模板必须指定参数类型// 但是在自己的虚拟机上不指定,编译和运行也是可以的// 在实际使用中后,还是现实指定类型比较规范Point_T int_point3(10, 20);Point_T<float, float> float_point1(1.1f, 2.2f);Point_T<float, float> float_point2(10.10f, 20.20f);Point_T<int, int> int_total_point;Point_T<float, float> float_total_point;int_total_point = int_point1 + int_point3;float_total_point = float_point1 + float_point2;std::cout << int_total_point << std::endl;std::cout << float_total_point << std::endl;return 0;
}

通过 objdump 也能看出来,代码中根据参数类型对类进行了实例化。

3 常见问题

3.1 模板列表中能不能有具体的数据类型

如下代码,模板列表中有一个类型是基本数据类型是  int,这种方式是合法的,编译运行都没问题。不过在开发中基本不这么使用,在实际使用中,模板列表都是抽象的类型,而不是具体的类型。

#include <iostream>
#include <string>template <class T, int data>
class Test {
public:void Do() {std::cout << "data = " << data << std::endl;}
};int main() {Test<int, 1> t1;Test<int, 10> t2;Test<int, 100> t3;t1.Do();t2.Do();t3.Do();return 0;
}

使用 objdump 可以看到,在代码段生成了 3 份 Do() 函数。

 

3.1 模板特化

3.1.1 函数模板特化

如下 IsEqual() 是一个模板函数,但是在参数类型是 char * 的时候,使用 t1 == t2 来判断是不对的。针对 char * 类型,可以将模板特化,也就是单独写一个判断字符串是否相等的函数。

函数模板的特化就是在函数上面写一个空的模板列表 template<>,然后函数的参数类型写成具体的数据类型就可以。

#include <iostream>
#include <string>
#include <cstring>template <class T>
bool IsEqual(T t1, T t2) {return t1 == t2;
}// 模板特化
template <>
bool IsEqual(char *t1, char *t2) {return strcmp(t1, t2) == 0;
}int main() {char str1[] = "hello";char str2[] = "hello";std::cout << IsEqual(10, 10) << std::endl;std::cout << IsEqual(str1, str2) << std::endl;return 0;
}

 

3.1.2 类模板的特化

类的特化和函数的特化类似,在累的声明前边声明一个空的模板列表,然后在类名后边声明具体的数据类型。

#include <iostream>
#include <string>
#include <cstring>template <class T>
class Compare {
public:bool IsEqual(T t1, T t2) {return t1 == t2;}
};// 模板特化
template <>
class Compare<char *> {
public:bool IsEqual(char* t1, char* t2) {return strcmp(t1, t2) == 0;}
};int main() {char str1[] = "hello";char str2[] = "hello";Compare<int> c1;Compare<char *> c2;std::cout << c1.IsEqual(10, 10) << std::endl;std::cout << c2.IsEqual(str1, str2) << std::endl;return 0;
}

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

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

相关文章

PowerBI怎么修改数据库密码

第一步&#xff1a;点击转换数据 第二步&#xff1a;点击数据源设置 第三步&#xff1a;点击编辑权限 第四步&#xff1a;点击编辑 第五步&#xff1a;输入正要修改的密码就可以了

分享几种简约大方的ListView外观设计(qml)

一、前言 最近才学到这里&#xff0c;感觉基础的 ListView 很丑&#xff0c;就现学现用弄个几个自认为还行的设计给大家献丑了。如果你觉得还不错&#xff0c;代码就在下面拿去直接用&#xff0c;顺便给我点个赞哈 ~ 感谢感谢 ~ 二、正文 设计1 第一种就是正常的左侧边栏&am…

LabVIEW管道缺陷智能检测系统

LabVIEW管道缺陷智能检测系统 管道作为一种重要的输送手段&#xff0c;其安全运行状态对生产生活至关重要。然而&#xff0c;随着时间的推移和环境的影响&#xff0c;管道可能会出现老化、锈蚀、裂缝等多种缺陷&#xff0c;这些缺陷若不及时发现和处理&#xff0c;将严重威胁到…

QGIS3.34官方版本已经不能支持Win7,如果需要在WIN7上使用,请用微云上我打包的

在网上看到有些网友在WIN7上安装官方发布的QGIS安装&#xff0c;会遇到上述问题&#xff0c;而不能正常运行&#xff01; 我打包的QGIS可以在WIN7上正常运行&#xff0c;这个我专门测试过。 详见&#xff1a; 打包了一个QGIS3.34分享给大家 下载地址&#xff1a;文件分享 软…

算法学习:双指针学习--左右指针

一&#xff1a;课前讲解 在处理数组和链表相关问题时&#xff0c;双指针技巧是经常用到的&#xff0c;双指针技巧主要分为两类&#xff1a;左右指针和快慢指针。 对于单链表来说&#xff0c;大部分技巧都属于快慢指针&#xff0c;在数组中并没有真正意义上的指针&#xff0c;但…

LeetCode # 547. 省份数量

547. 省份数量 题目 有 n 个城市&#xff0c;其中一些彼此相连&#xff0c;另一些没有相连。如果城市 a 与城市 b 直接相连&#xff0c;且城市 b 与城市 c 直接相连&#xff0c;那么城市 a 与城市 c 间接相连。 省份 是一组直接或间接相连的城市&#xff0c;组内不含其他没有…

wsl 安装 ubuntu

文章目录 打开Windows PowerShell查看可安装的ubuntu安装相对应的ubuntu将用户添加到sudoers文件中&#xff0c;并赋予了该用户sudo权限。 打开Windows PowerShell 以管理员的身份运行 查看可安装的ubuntu wsl.exe --list --online安装相对应的ubuntu wsl --install 版本…

Qt for WebAssembly : Application exit (SharedArrayBuffer is not defined)

用Qt开发 WebAssembly&#xff0c;放到nginx里面&#xff0c;用127.0.0.1访问没问题&#xff0c;用局域网IP访问就提示如下&#xff1a; 总结了以下两种解决办法&#xff1a; ①&#xff1a;配置 nginx http 头 [ 支持&#xff1a;WebAssembly Qt (single-threaded) ] ②&#…

汉诺塔问题(C语言)

一&#xff1a;问题 汉诺塔&#xff08;Tower of Hanoi&#xff09;&#xff0c;又称河内塔&#xff0c;是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从…

Ubuntu环境配置-LinuxQQ篇

本教程下载Linux QQ的版本是linuxqq_3.0.0-571_amd64.deb 一、下载LinuxQQ 直接使用wget命令下载链接&#xff0c;下载文件 wget https://dldir1.qq.com/qqfile/qq/QQNT/c005c911/linuxqq_3.0.0-571_amd64.deb 二、安装LinuxQQ 当下载完成后&#xff0c;运行命令&#xff1a;…

【计算机网络笔记】1.概论

【计算机网络笔记】1.概论 前言: 计算机网络概论学习过程中,我感觉它就是在问一个问题: 计算机之间如何实现高效通信? 计算机网络的名词解释 重要基本特点 1.连通性 2.资源共享计算机网络的组成 由若干节点node和连接这些节点的链路link组成。节点可以是计算机、集线器、交换…

供应链管理(SCM):界面设计全面扫盲,得供应链者得天下

大家伙&#xff0c;我是大千UI工场&#xff0c;专注UI分享和项目接单&#xff0c;本期带来供应链系统的设计分享&#xff0c;欢迎大家关注、互动交流。 一、什么是SCM SCM系统是供应链管理&#xff08;Supply Chain Management&#xff09;系统的缩写。供应链管理是指协调和管…

openEuler全球生态合作研讨会:共话全球技术创新,共建国际产业生态

2024年2月27日&#xff0c;OpenAtom openEuler&#xff08;简称“openEuler”&#xff09;全球生态合作研讨会在西班牙巴塞罗那成功举办。开放原子开源基金会副秘书长辛晓华先生&#xff0c;开放原子开源基金会开源安全委员会副主席任旭东先生&#xff0c;Eclipse基金会首席会员…

linux安装openGauss数据库

这里写自定义目录标题 linux安装openGauss数据库openGauss 安装与配置传统安装docker安装 linux安装openGauss数据库 openGauss是一款华为开源的关系型数据库管理系统&#xff0c;它具有多核高性能、全链路安全性、智能运维等企业级特性。 openGauss内核早期源自开源数据库Po…

VMware虚拟机安装Linux教程(超详细)

目录 一、安装VMware VMware下载&#xff08;16 pro&#xff09;&#xff1a; 镜像文件&#xff08;不一定选择CentOS&#xff0c;只是为了有图形界面更好的操作)​ 安装VMware 安装虚拟机 第一步&#xff1a;点击创建新的虚拟机。​ 第二步&#xff1a;选择自定义 &…

2024电子商务与互联网技术国际会议(ICECIT 2024)

2024电子商务与互联网技术国际会议&#xff08;ICECIT 2024) 一、【会议简介】 2024电子商务与互联网技术国际会议&#xff08;ICECIT 2024&#xff09;将于2024年在杭州举行。这是一个重要的学术会议&#xff0c;旨在汇集全球的专家、学者和业界领袖&#xff0c;共同探讨电子…

VS2022打包C#安装包(最新、最全)

开发c#的一个小工具到打包环境碰壁了&#xff0c;在网上找了很多资料耶踩了很多坑&#xff0c;耗时1hour才打包完毕&#xff0c;避免以后碰到类似的问题再次记录&#xff0c;自认为步骤比较全面&#xff0c;如果有帮助麻烦点个赞呗&#xff01;&#xff01;&#xff01; 一、Mi…

实现vue elmentUI图片本地上传

实现思路 后端代码 //上传头像PostMapping("/uplaod")public String upload(MultipartFile file) { // System.out.println(file"图片上次");//图片校验if (file.isEmpty()) {return "图片上传失败";}//可以自己加一点校验 例如上传的是不…

解决 RuntimeError: “LayerNormKernelImpl“ not implemented for ‘Half‘

解决 RuntimeError: “LayerNormKernelImpl” not implemented for ‘Half’。 错误类似如下&#xff1a; Traceback (most recent call last): File “cli_demo.py”, line 21, in for results in webglm.stream_query(question): File “/root/WebGLM/model/modeling_webgl…

Polar 写shell

Polar 写shell 直接给了源码 还是没啥好说的&#xff0c;考点是die()死亡函数绕过之不同变量 **绕过原理&#xff1a; **通过base64解密或rot13解密使"<?php exit();"变为乱码&#xff0c;而传入的$content为base64编码&#xff0c;解码后为正常shell语句。通过…