首页 > 其他分享 >模板的简单使用

模板的简单使用

时间:2023-08-03 12:35:24浏览次数:41  
标签:函数 实例 简单 编译器 Vector 使用 模板 size

这篇博客主要是简单的介绍函数模板和类模板的使用。

函数模板

假设现在需要你写多个交换函数用于各种类型的交换,如果一个一个写的话那即浪费时间,也会让代码整体不好看。

那么为了解决这种情况就可以使用函数模板。

例如下面:

using namespace std;
// 模板函数
template<class T>//如果你需要的模板函数具有多个参数
//则中间使用,分割例如:template<class T,class T1,1>
void Swap(T& left, T& right)
{
    T tmp = left;
    left = right;
    right = tmp;
}//函数模板
int main()
{
    int a = 2, b = 3;
    double a1 = 2.3, b1 = 3.3;

    Swap(a, b);
    cout <<"a = " << a << " " <<"b = " << b << endl;

    Swap(a1, b1);
    cout<<"a1 = " << a1 << " " <<"b1 = " << b1 << endl;

    return 0;
}

模板的简单使用_编译器

那么这里为什么能够运行呢?在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然 后产生一份专门处理double类型的代码,对于整型类型也是如此。

这里需要注意的是函数模板和模板函数是两个不同的概念,函数模板是我们写给编译器的,函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

而模板函数则是编译器通过函数模板生成的函数。如下图

模板的简单使用_实例化_02

中间的是函数模板,而右边的便是编译器生成的模板函数。

函数模板的实例化

函数模板的实例化分成两种,一种位隐式实例化,一种为显示实例化

隐式实例化:也就是让编译器通过实参推演模板参数的实际类型,例如一开始的交换函数。

显示实例化

以一个加法函数为例子

template<class T>
T Add(const T& a,const T& b)
{
    return a + b;
}//函数模板

这里可以使用隐式实例化但是如果我传入的实参一个是整型一个是浮点型,如果不做任何处理是会直接报错的,那么要怎么处理呢?

第一种方法也就是强制类型转换,即要么将整型转为浮点型,要么将浮点型转化为整型。

第二种方法也就是显示实例化即让我们自己告诉编译器要实例化成哪种模板函数。

例如下面这样

int main()
{
    int a = 2, b = 3;
    double a1 = 2.3, b1 = 3.3;
    cout << "a+b1 = " << Add<int>(a, b1) << endl;
    return 0;
}

模板的简单使用_编译器_03

这里因为进行了强制类型转换,所以会将小数删除。

模板参数的匹配原则

假设你不仅写了一个int的Add函数也写了一个Add函数的模板,那么在不同的情况下编译器会如何匹配呢?

template<class T>
T Add( const T& a,  const T& b)
{
    return a + b;
}//函数模板
int Add(int a, int b)
{
    cout << "调用了现存的函数" << endl;
    return a + b;
}//具体的加法函数
int main()
{
    int a = 3, b = 5;
    cout<<"a+b = " << Add(a, b) << endl;//整型
    double a1 = 2.23, b1 = 3.35;
    cout << "a1+b1 = " << Add(a1, b1) << endl;//浮点型
    return 0;
}

模板的简单使用_实例化_04

可以看到对于int类型的加法,编译器直接调用了现存的函数,而不是自己生成。而对于double则是自己生成的。

由此可以得出结论:对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。

如果这里你强制要编译器自己写一个函数用于int加法,那么直接使用显示实例化即可。

最后还有一点需要注意:模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

类模板

既然一个函数可以有模板那么同样的一个类自然也可以用模板。需要注意的点就是类模板在使用的时候必须显示实例化。下面是一个栈的模板。

// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>//如果需要定义多个T方式和函数一样,分割即可
class Vector
{
public:
    Vector(size_t capacity = 10)
        : _pData(new T[capacity])
        , _size(0)
        , _capacity(capacity)
    {}

    // 使用析构函数演示:在类中声明,在类外定义。
    ~Vector();

    void PushBack(const T& data);
        size_t Size() { 
            return _size; 
        }

    T& operator[](size_t pos)
    {
        //assert(pos < _size);
        return _pData[pos];
    }

private:
    T* _pData;
    size_t _size;
    size_t _capacity;
};
//如果你想要将类模板进行声明和定义分离,那么需要下面这么写(这里以析构函数为例)
template <class T>
Vector<T>::~Vector()//不能Vector::~Vector()这么写因为Vector不是类名而只是编译器生成时使用的模具类名
//Vector<T>这样的显示实例化后才是类名。
{
    if (_pData)
        delete[] _pData;
    _size = _capacity = 0;
}
template <class T>
void Vector<T>::PushBack(const T& data)
{
    _pData[_size] = data;
    _size++;
}
int main()
{
    Vector<int> s1;//使用的时候必须显示实例化
    s1.PushBack(1);
    s1.PushBack(2);
    s1.PushBack(3);
    return 0;
}

模板的简单使用_编译器_05

这篇博客只是简单的介绍了模板的简单应用,希望能对您有所帮助,感谢如果发现任何错误,欢迎指出。



标签:函数,实例,简单,编译器,Vector,使用,模板,size
From: https://blog.51cto.com/u_15838996/6947976

相关文章

  • 深入浅出RxJava (四:在Android中使用响应式编程)
    [url=http://blog.danlew.net/2014/10/08/grokking-rxjava-part-4/]原文链接[/url]在第1,2,3篇中,我大概介绍了RxJava是怎么使用的。下面我会介绍如何在Android中使用RxJava.RxAndroidRxAndroid是RxJava的一个针对Android平台的扩展。它包含了一些能够简化And......
  • Python开发实例(二)To-Do列表应用:创建一个简单的命令行应用,允许用户添加、删除和查看待
    defprint_todo_list(todo_list):ifnottodo_list:print("待办事项列表为空!")else:print("待办事项列表:")forindex,todoinenumerate(todo_list,1):print(f"{index}.{todo}")defadd_todo(todo_......
  • 【Linux】Kali Linux 渗透安全学习笔记(2) - OneForAll 简单应用
    OneForAll(以下简称“OFA”)是一个非常好用的子域收集工具,可以通过一级域名找到旗下的所有层级域名,通过递归的方式我们很容易就能够知道此域名下的所有域名层级结构,对于进一步通过域名推测站点功能起到非常重要的作用。声明:本文测试的站点为自家站点仅做学习使用,不存在侵犯网络......
  • python使用mqtt
    一、安装mqtt服务器安装对应的软件:https://www.emqx.io/zh/downloads推荐使用docker安装默认账号和密码:admin、public 二、编写代码消息发布程序importtimeimportjsonimportpsutilimportrandomfrompaho.mqttimportclientasmqtt_clientbroker='127.0.0.1......
  • ThreeJs实现简单的动画
    上一节实现可用鼠标控制相机的方式实现动态效果,但很多时候是需要场景自己产恒动态效果,而不是通过鼠标拖动,此时引入一个requestAnimationFrame方法,它实际上是通过定时任务的方式,每隔一点时间改变场景中内容后重新渲染一遍,间隔时间短的话视觉上就显示出连续的动画效果,Js本身也自带定......
  • 记录使用uview的tabs组件初始化渲染下划线移位问题解决
    问题描述:初始化渲染后tabs的下划线没有居中对其,出现异位。问题分析: 网上很多大佬分析过出现原因了记录下解决的过程: 在各个论坛搜集到解决方案都暂时无效 有使用v-if重新渲染的  有给类赋值偏移值的 有强行转换px的因为各种原因这些方法在自己身上没有奏效所以记......
  • Jemeter安装与简单使用
    安装Jemeter1.下载官网地址下载完成之后进行解压安装2.下载MySQL数据库驱动然后将数据库驱动放在jemeter安装目录的bin目录下面。3.启动点击bin目录下的jmeter.bat设置语言为中文使用Jemeter对MySQL进行压力测试1.添加线程组选择线程组配置线程组信息......
  • RPA开发复杂流程-为什么使用编码自动化而不是低代码?
    答:编码自动化可以让任何熟悉编码或脚本的人都能体验到更高的生产力、更好的复杂性管理、更高的协作和可审查性、改进的可读性和更高的性能。 ......
  • Linux环境下,使用远程连接工具过程中终端无法弹出图形窗口
    Linux操作系统,请通过管理网口/VNC等远程连接工具登录服务器,使用终端执行操作。如果在使用过程中无法弹出图形窗口,请执行以下操作。场景一:使用SSH连接工具登录LINUX服务器确保工具支持远程图形显示。SSH连接工具需要支持远程图形显示,才能弹出图形窗口。putty、SecureCRT默认......
  • kratos项目中使用kafka实现延迟队列
    项目地址https://gitee.com/huoyingwhw/kratos_kafkaB站视频地址B站视频地址——kratos项目中使用kafka实现延迟队列......