C++模板详解——使用篇

时间:2022-09-10 12:04:40

假如我们需要取得两个变量中较大的变量,或许,我们可以通过重载的方式实现,如下。

int max(int fir,int sec);
float max(float fir,float sec);
double max(double fir,double sec);

有一天,我们定义了一个新的type,School,取决于max的实现,我们不仅需要重载School::operator<(), 或者School::operator>()还要重载一个新的max

const School max(School& fir,School& sec);

使用C++的模板,从此告别这些繁琐而又略显臃肿的代码。

注:1. 上述的返回值可以考虑使用const School&,但一般不建议,参见在返回值拒绝reference

2.形参使用了School&,参见传参时,使用引用替换变量

函数模板##

顾名思义,模板,也就是“模板”,并不是实际存在的东西,而只是为了让我们更方便地生产某些东西的模具。C++的模板分为了两类,类模板与函数模板。分别用于让我们方便地“生产各种各样的函数与类”,它们都使用了template,class,typename几个关键字。为什么说是各种各样,看完了博客自然就明白了。下面介绍函数模板。

示例####

template < class type>
type max(type fir,type sec)
{
return fir > sec ? fir : sec;
}

template告诉编译器这是一个模板,紧跟在后面的<>中声明了模板形参,这些形参在模板中可以充当类型,声明可以选用class或者typename,暂时认为两者在C++中作用相同。普通函数的形参为一个变量,模板形参为一种变量类型。也就是,我们可以通过指定模板形参的类型。来个简单的例子。

比如int,float来形成不同的重载函数

template < class type...>
type max(type fir,type sec...)
{
return fir > sec ? fir : sec;
}
void main()
{
int a(1),b(2);
float c(1),d(2);
max(a,b); //具现化int max(int fir,int sec);
max(c,d); //具现化int max(float fir,float sec);
}

第一个max使用了int类型的参数,相当于告诉函数模板,type对应于int,在具现化的函数模板中,type的作用相当于int。所以具现化的函数相当于int

max(int fir,int sec);相对应地,使用了float调用函数模板,也就是制定了type为float,与前一个函数形成了重载。

注:虽然float能够隐私转换为int,但是还是会具现化新的函数。只有当前的参数类型与已经具现化的函数模板完全匹配的时候,才会继续使用已经具现化的函数。

拓展####

template < class type_1,class type_2...>
type_1 func(type_2 fir,type_1 sec,int thir)
{
//return...
}

相对于前一个模板函数,这个模板函数的模板形参数量增加了,在普通的形参列表中,模板形参的顺序打乱了,还增加了int的形参。

  1. 在模板形参中,我们可以随意地定义任意数量的模板形参,但必须保证能够全部初始化。
  2. 使用了不同的类型名type_1,type_2...意味着我们可以指定多种类型的模板形参,其类型也可以不相同。
  3. 模板形参没有要求必须与普通函数形参一一对应,即在形参中的顺序可以随意打乱,其类型由相应的普通形参的类型决定。如,type_1的类型由sec的类型决定。
  4. 在模板函数中,除了模板形参外,可以使用内置的或者自定义的类型。

还是来个简单的例子

template < class type_1,class type_2>
void max(type_2 fir,type_1 sec,int)//最后的参数没有使用,可以直接忽略形参名
{
std::cout<<fir<<"+"<<sec<<endl;
}
void main()
{
int a(1);
float b(1.0);
max(a,b,1); //1. 具现化void max(int fir,float sec,int);
}

第一个实参为int型,其对应的形参是type_2,所以type_2具现化后就是int。

第二个实参为float,其对应的形参type_1,所以type_1具现化后就是float。最后的具现化的函数就是int max(int fir,float sec,int);

指定参数类型####

还记得使用STL容器的方法吗,比如定义一个vector类型的容器。STL也叫作标准模板库,也就是其内部也是通过模板实现的,所以这种名称后加类型名的方法对我们也同样适用。

void Select(int a)
{
std::cout<<"是int型"<<endl;
}
void Select(float a)
{
std::cout<<"是float型"<<endl;
}
template < class type_1,class type_2>
void myPrint(type_1 fir,type_2 sec)
{
Select(fir);
}
void main()
{
myPrint(1.0,1); //输出"是float型"
myPrint<int>(1.0,1); //输出"是int型"
}

在上面的例子中,我们可以发现:

  1. 在调用模板函数的时候,我们可以通过直接指定模板形参的类型从而阻止普通函数形参对于模板形参的影响。但是,指定的类型与普通函数形参必须能够进行类型转换。

比如,内置类型的int与double可以相互转换,所以myPrint< double>(1)可用。但是string与int之间不可相互转换myPrint< string>(1)就没办法通过编译。假如我们定义了class My,其构造函数为public:My(int),那么认为My与int可以相互转换(本质上是隐式调用了My的构造函数),myPrint< My>(1)就可以通过编译。

类模板##

假如你对函数模板还不会使用,请自行回顾,一些函数模板讲过的在下面不再赘述。

实例##

template < class type_1,class type_2>
class Student
{
public:
Student(){}
Student(type_1 fir,type_2 sec){}
Student(type_1 fir){}
private:
type_1 value_1;
type_2 value_2;
...
};
void main()
{
Student stu(1,1); //error
Student<int,float> stu(1,1); //OK
}

template,class的作用与函数模板一致。不同的是:

  1. 类模板必须在使用的时候指定好模板形参的类型,编译器不会通过public接口,包括构造函数去作为模板形参类型的辨别依据。记得vector vec吧,没见过vector vec(1)吧。
  2. 使用类模板的时候,使用到的成员函数在主调语句必须可见。比如,上述的Student(type_1 fir,type_2 sec)在main中调用,其函数定义在main所在文件必须可见。再比如上述例子,假如其实现分配到如下几个文件,在链接的时候将出错。读者可以先记得,在“精通篇”会详细阐述这一点。
  3. 类模板中,慎用模板形参重载函数。上述的例子中,假如再增加Student(type_2)就会编译出错。编译器无法在Student(type_1)与Student(type_2)中做抉择。
//1.h
template < class type_1,class type_2>
class Student
{
public:
...
Student() //有具体实现的构造函数
{
...
}
Student(type_1 fir,type_2 sec);
private:
...
};
//1.cpp
#include"1.h"
Student< class type_1,class type_2>::Student()
{}
//core.cpp
#include"1.h"
void main()
{
Student<int,int> stu(1,1); //构造函数定义在1.cpp中,不可见,出错
Student<int,int> stu(); //默认构造函数随1.hinclude,可见,编译通过
}

C++中模板的基本使用方法如上。下一篇博客将带大家进入模板特化以及深入解释上述例子无法编译的原因。

C++模板详解——使用篇的更多相关文章

  1. C&plus;&plus; 类模板详解&lpar;一&rpar;:概念和基本使用方式

    与函数模板类似地(C++函数模板详解(一):概念和特性) ,类也可以被一种或多种类型参数化.例如,容器类就是一个具有这种特性的典型例子,它通常被用于管理某种特定类型的元素.只要使用类模板,我们就可以实 ...

  2. C&plus;&plus;模板详解&lpar;三&rpar;:参数化声明详解

    在前两节中(C++模板详解(一).C++模板详解(二)),我们了解了函数模板和类模板的基本概念和使用方法.在这篇博文里,我们主要来详细地阐述一下"模板的参数声明"这个话题,并且也谈 ...

  3. 微信授权步骤与详解 -- c&num;篇

    微信授权步骤与详解 -- c#篇 注:这里不涉及界面操作,只介绍代码操作. 1.基本原理如下: 从图上所知,第一步用户访问我们的网页,第二步我们后台跳转到微信授权页面,第三步用户点击授权,第四步微信重 ...

  4. bt协议详解 DHT篇(下)

    bt协议详解 DHT篇(下) 最近开发了一个免费教程的网站,产生了仔细了解bt协议的想法,这篇文章是bt协议详解系列的第三篇,后续还会写一些关于搜索和索引的东西,都是在开发这个网站的过程中学习到的技术 ...

  5. bt协议详解 DHT篇(上)

    bt协议详解 DHT篇(上) 最近开发了一个免费教程的网站,突然产生了仔细了解bt协议的想法,这篇文章是bt协议详解系列的第三篇,后续还会写一些关于搜索和索引的东西,都是在开发这个网站的过程中学习到的 ...

  6. IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm(转载)

    IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm 自从本系列发布之后,收到了很多的朋友的回复!非常感谢,同时很多朋友问到了一些问题,有些问 ...

  7. IIS负载均衡-Application Request Route详解第一篇: ARR介绍(转载)

    IIS负载均衡-Application Request Route详解第一篇: ARR介绍 说到负载均衡,相信大家已经不再陌生了,本系列主要介绍在IIS中可以采用的负载均衡的软件:微软的Applica ...

  8. C&plus;&plus;模板详解

    参考:C++ 模板详解(一) 模板:对类型进行参数化的工具:通常有两种形式: 函数模板:仅参数类型不同: 类模板:   仅数据成员和成员函数类型不同. 目的:让程序员编写与类型无关的代码. 注意:模板 ...

  9. 25&period;C&plus;&plus;- 泛型编程之函数模板&lpar;详解&rpar;

    本章学习: 1)初探函数模板 2)深入理解函数模板 3)多参函数模板 4)重载函数和函数模板 当我们想写个Swap()交换函数时,通常这样写: void Swap(int& a, int&am ...

随机推荐

  1. C&num;设置通过代理访问ftp服务器

    // 创建FTP连接 private FtpWebRequest CreateFtpWebRequest(string uri, string requestMethod) { FtpWebReque ...

  2. sass跨文件重写变量

    利用变量默认值: !default 你可以在变量尚未赋值前,通过在值的末尾处添加 !default 标记来为其指定. 也就是说,如果该变量已经被赋值, 就不会再次赋值, 但是,如果还没有被赋值,就会被 ...

  3. Unity3d&colon;编辑器中运行正常,发布后的exe提示找不到文件

    解决方案1:查看文件路径拼写方式,如果是用“+”拼接的,请改用System.IO.Path.Combine()方式拼接.经过测试,两种拼接方式打印出来的路径是一样的,但为什么 加号 的方式拼接unit ...

  4. 时序列数据库武斗大会之什么是 TSDB ?

    本文选自 OneAPM Cloud Insight 高级工程师刘斌博客 . 刘斌,一个才思敏捷的程序员,<第一本 Docker 书>.<GitHub 入门与实践>等书籍译者,D ...

  5. bzoj1503 &lbrack;NOI2004&rsqb;郁闷的出纳员(名次树&plus;懒惰标记)

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 8705  Solved: 3027[Submit][Statu ...

  6. 是否可能两个ETH私钥对应同一个地址

    原提问在这里. 笔者在使用到neon-js中的私钥生成方法时发现其使用了getRandomValues方法来生成64字符长度的私钥,进而考虑到其随机性,若是调用足够多次,依然有可能生成两个完全一样的私 ...

  7. DOM事件阶段以及事件捕获与事件冒泡先后执行顺序

    平时浏览这么多技术文章,如过不去实践.深入弄透它,这个技术点很快就会在脑海里模糊.要加深印象,就得好好过一遍.重要的事情说三遍,重要的知识写一遍. 开发过程中我们都希望使用别人成熟的框架,因为站在巨人 ...

  8. 【转】iPhone易被窃听应用三分钟即可获取所有信息

    2011年8月9日10:19 “你有iPhone吗?这下你麻烦了!”昨天香港<东方日报>封面文章用这样的语气报道说,一种iPhone等智能手机窃听程序,正引爆香港. 该报记者亲自试验,发现 ...

  9. 使用 numpy&period;random&period;choice随机采样

    使用 numpy.random.choice随机采样: 说明: numpy.random.choice(a, size=None, replace=True, p=None) 示例: >> ...

  10. cmd&period;exe启动参数详解

    https://blog.csdn.net/moonhillcity/article/details/53039763 各个系统中打开文件的命令 "windows系统: cmd " ...