首页 > 编程语言 >C++——模板初阶

C++——模板初阶

时间:2024-04-10 23:32:22浏览次数:21  
标签:初阶 函数 int C++ 编译器 right 模板 left

目录

0.前言

1. 泛型编程

2. 函数模板

2.1 函数模板概念

2.1 函数模板格式

2.3 函数模板的原理

2.4 函数模板的实例化

2.5 模板参数的匹配原则

3. 类模板

3.1 类模板的定义格式

3.2 类模板的实例化


0.前言

C++模板是一种泛型编程的工具,允许开发者定义对多种数据类型都适用的代码。模板提供了代码重用的机制,使得开发者可以编写与数据类型无关的代码。C++模板分为函数模板和类模板。

1. 泛型编程

如何实现一个通用的交换函数呢?
void Swap(int& left, int& right)
{
 int temp = left;
 left = right;
 right = temp;
}
void Swap(double& left, double& right)
{
 double temp = left;
 left = right;
 right = temp;
}
void Swap(char& left, char& right)
{
 char temp = left;
 left = right;
 right = temp;
}
使用函数重载虽然可以实现,但是有一下几个不好的地方: 1. 重载的函数仅仅只是类型不同,代码的复用率比较低,只要有新类型出现时,就需要增加对应的函数 2. 代码的可维护性比较低,一个出错可能所有的重载均出错 那能否 告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码 呢? 如果在 C++ 中,也能够存在这样一个 模具 ,通过给这个模具中 填充不同材料 ( 类型 ) ,来 获得不同材料的铸件( 生成具体类型的代码) ,那将会节省许多头发。巧的是前人早已将树栽好,我们只需在此乘凉。 泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

2. 函数模板

2.1 函数模板概念

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

2.1 函数模板格式

template<typename T1, typename T2,......,typename Tn> 返回值类型 函数名 ( 参数列表 ){}
template<typename T>
void Swap( T& left, T& right)
{
 T temp = left;
 left = right;
 right = temp;
}
注意: typename 用来定义模板参数 关键字也可以使用 class( 切记:不能使用 struct 代替 class)

2.3 函数模板的原理

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器 在编译器编译阶段 ,对于模板函数的使用, 编译器需要根据传入的实参类型来推演生成对应类型的函数 以供调用。比如: 当用 double 类型使用函数模板时,编译器通过对实参类型的推演,将 T 确定为 double 类型,然 后产生一份专门处理 double 类型的代码 ,对于字符类型也是如此。

2.4 函数模板的实例化

用不同类型的参数使用函数模板时 ,称为函数模板的 实例化 。模板参数实例化分为: 隐式实例化和显式实例化 。 1. 隐式实例化:让编译器根据实参推演模板参数的实际类型
template<class T>
T Add(const T& left, const T& right)
{
 return left + right;
}
int main()
{
 int a1 = 10, a2 = 20;
 double d1 = 10.0, d2 = 20.0;
 Add(a1, a2);
 Add(d1, d2);
 
 /*
 该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
 通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,
 编译器无法确定此处到底该将T确定为int 或者 double类型而报错
 注意:在模板中,编译器一般不会进行类型转换操作
 Add(a1, d1);
 */
 
 // 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化
 Add(a, (int)d);
 return 0;
}
2. 显式实例化:在函数名后的 <> 中指定模板参数的实际类型
int main(void)
{
 int a = 10;
 double b = 20.0;
 
 // 显式实例化
 Add<int>(a, b);
 return 0;
}
如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

2.5 模板参数的匹配原则

1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
// 专门处理int的加法函数
int Add(int left, int right)
{
 return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
 return left + right;
}
void Test()
{
 Add(1, 2); // 与非模板函数匹配,编译器不需要特化
 Add<int>(1, 2); // 调用编译器特化的Add版本
}
2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。
// 专门处理int的加法函数
int Add(int left, int right)
{
 return left + right;
}
// 通用加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
 return left + right;
}
void Test()
{
 Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化
 Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
}
3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

3. 类模板

3.1 类模板的定义格式

template<class T1, class T2, ..., class Tn>
class 类模板名
{
 // 类内成员定义
};

3.2 类模板的实例化

类模板实例化与函数模板实例化不同, 类模板实例化需要在类模板名字后跟 <> ,然后将实例化的类型放在 <>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类
// Vector类名,Vector<int>才是类型
Vector<int> s1;
Vector<double> s2;

标签:初阶,函数,int,C++,编译器,right,模板,left
From: https://blog.csdn.net/2301_80206366/article/details/137615360

相关文章

  • QtCreator配置C++20开发环境
    我不知道你的QtCreator是什么版本的,但是我觉得操作方案是相同的,让QtCreator编译C++20代码,需要你有一个支持C++20的编译器,不管你是msvc还是gcc,总要有一个。如果你和我一样,用的5.12.12,那真的太巧了,请看步骤吧:配置kit:首先你应该有一个Qt版本的列表,如果没有,请你自行添加,添加的方式......
  • 第十二届蓝桥杯省赛真题(C/C++大学B组)
    目录#A空间#B卡片#C直线#D货物摆放#E路径#F时间显示#G砝码称重#H 杨辉三角形#I双向排序#J括号序列#A空间#include<bits/stdc++.h>usingnamespacestd;intmain(){ cout<<256*1024*1024/4<<endl; return0;}#B卡片#include<bit......
  • C/C++学习笔记-eclipse不支持C++11问题
    转 https://blog.csdn.net/qq_35703954/article/details/81540315std::thread的使用,结果编译报错信息如下: 问题分析:查看错误提示,发现thread不是命名空间std的一个成员,那么我们知道thread很明显是std的成员,那么久只有一种可能:即没有引入相关的头文件,但是检查发现,头文件也有。又......
  • 【模板】任意模数多项式乘法:三模 NTT
    前置知识https://www.cnblogs.com/caijianhong/p/template-crt.htmlhttps://www.cnblogs.com/caijianhong/p/template-fft.html题目描述任意模数多项式乘法solution首先我们打开https://blog.miskcoo.com/2014/07/fft-prime-table这篇文章找到\(998244353\)附近的几个质......
  • C++ 标准库类型priority_queue
    C/C++总述:StudyC/C++-CSDN博客 堆(数据结构):堆-CSDN博客priority_queue(优先队列)在优先队列中,元素被赋予优先级(按约定的函数来赋予优先级,底层通过堆来实现)。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出(firstin,largestout)的行为特征。定义......
  • 《C++程序设计》阅读笔记【7-堆和拷贝构造函数】
    ......
  • C++ 获取数组大小、多维数组操作详解
    获取数组的大小要获取数组的大小,可以使用sizeof()运算符:示例intmyNumbers[5]={10,20,30,40,50};cout<<sizeof(myNumbers);结果:20为什么结果显示为20而不是5,当数组包含5个元素时?这是因为sizeof()运算符返回类型的大小(以字节为单位)。要找出数组有多少......
  • C++ Primer Plus(第6版):封装、继承与多态
    C语言编程原理C语言在最初面试时是一种过程性(procedural)语言,这意味着它强调的是编程的算法方面,程序命令计算机按照一系列流程生成特定的结果。但是随着程序规模的扩大,程序经常使用分支语句,很多旧式程序的执行路径很混乱(被称为“意大利面条式编程”,突出一个混乱程度)。计算机科学家......
  • 突破编程_C++_网络编程(Windows 套接字(阻塞模式与非阻塞模式))
    1阻塞模式与非阻塞模式的概念(1)阻塞模式概念:在阻塞模式下,当套接字执行I/O操作时,如果操作不能立即完成,调用函数会一直等待直到操作完成。在等待期间,执行操作的线程会被阻塞,无法继续执行其他任务。特点:简单直观:对于许多简单的网络应用来说,阻塞模式编程简单直观,易于理......
  • c++11实现线程池
    c++11实现线程池c++线程库thread创建线程和同步的方式jion,detach#include<iostream>#include<thread>voidprintf_hw(std::strings){ std::cout<<s<<"\n";}intmain(){ std::threada(printf_hw,"nihao"); //a.join();//同步 a.de......