族谱网 头条 人物百科

模板

2020-10-16
出处:族谱网
作者:阿族小谱
浏览:314
转发:0
评论:0
语法模板的声明与定义模板定义以关键字template开始,后接模板形参表(templateparameterlist),模板形参表是用尖括号括住的一个或者多个模板形参的列表,形参之间以逗号分隔。模板形参可以是表示类型的类型形参(typeparameter),也可以是表示常量表达式的非类型形参(non-typeparameter)。非类型形参跟在类型说明符之后声明。类型形参跟在关键字class或typename之后声明。模板形参可以给出默认值(defaultargumentsfortemplateparameters)。模板的非类型形参模板的非类型形参(templatenon-typeparameter)允许为下述形式:整型或枚举型到对象的指针或函数指针到对象的引用或函数引用成员指针模板的非类型参数被声明为数组或函数的,将被转换为指针或函数指针。例如:模板的非类型形参允许用const或vol...

语法

模板的声明与定义

模板定义以关键字template开始,后接模板形参表(template parameter list),模板形参表是用尖括号括住的一个或者多个模板形参的列表,形参之间以逗号分隔。模板形参可以是表示类型的类型形参(type parameter),也可以是表示常量表达式的非类型形参(non-type parameter)。非类型形参跟在类型说明符之后声明。类型形参跟在关键字class或typename之后声明。模板形参可以给出默认值(default arguments for template parameters)。

模板的非类型形参

模板的非类型形参(template non-type parameter)允许为下述形式:

整型或枚举型

到对象的指针或函数指针

到对象的引用或函数引用

成员指针

模板的非类型参数被声明为数组或函数的,将被转换为指针或函数指针。例如:

模板的非类型形参允许用const或volatile限定(而模板的类型形参是不允许cv限定的)。模板的非类型形参是不允许声明为浮点型、class类型、void型。

模板的模板参数

类模板的模板参数允许是另外一个类模板,这称为模板的模板参数(template template parameter),也译作“模板参数模板”。函数模板不允许有模板的模板参数。例如:

模板参数的默认值

模板形参可以给出默认值(default arguments for template parameters)。如果一个模板参数给出了默认值,那么模板形参列表中在其后声明的模板参数都应该给出默认值。例如:

一个模板的各次声明给出的模板参数的默认值可以累积其效果。例如:

但是如果交换本示例第一行与第二行的次序,将编译报错。因为如果第一个模板参数T有了默认值,此时编译器必须已经知道其后的第二个模板参数U的默认值。

在同一个作用于(scope)中,不能对同一个模板的同一个参数多次声明其默认值。例如:

模板参数的作用域为从其声明之处至该模板的定义结束之处。因此可以使用一个模板参数作为其后声明的其他模板参数的一部分或默认值。例如:

变量模板

变量模板(variable template)是C++14引入的新的一个种类的模板。可用于在命名空间作用域声明一个变量。例如:

可以在类作用域声明一个静态数据成员:

类的静态数据成员模板,也可以用类模板的非模板数据成员来实现:

变量模板不能用作模板的模板参数(template template arguments)。

模板的使用

使用模板时,可以在模板名字后面显式给出用尖括号括住的模板实参列表(template argument list)。对模板函数或类的模板成员函数,也可不显式给出模板实参,而是由编译器根据函数调用的上下文推导出模板实参,这称为模板参数推导。

如果模板参数使用其默认值,则在模板实参列表中可以忽略它。如果所有的模板参数都使用了默认值,模板实参列表为空,但仍然必须写出成对的尖括号。例如:

对于作为类型的模板实参,不允许是局部类型(local type)、无链接性的类型(type with no linkage)、无名类型(unnamed type)或包括了这三种情形的复合类型。但C++11以及允许本地类型作为模板实参。

示例

函数模板

以下以取最大值的函数模板maximum为例。此函数在编译时会自动产生对应参数类型的代码,而不用显式声明。


类模板


模板的嵌套:成员模板

对于类中的模板成员函数、嵌套的成员类模板,可以在封闭类的内部或外部定义它们。当模板成员函数、嵌套类模板在其封闭类的外部定义时,必须以封闭类模板的模板参数(如果它们也是模板类)和成员模板的模板参数开头。

C++标准规定:如果外围的类模板没有特例化,里面的成员模板就不能特例化。

依赖名字与typename关键字

一个模板中的依赖于一个模板参数(template parameter)的名字被称为依赖名字 (dependent name)。当一个依赖名字嵌套在一个类的内部时,称为嵌套依赖名字(nested dependent name)。一个不依赖于任何模板参数的名字,称为非依赖名字(non-dependent name)。

编译器在处理模板定义时,可能并不确定依赖名字表示一个类型,还是嵌套类的成员,还是类的静态成员。C++标准规定:如果解析器在一个模板中遇到一个嵌套依赖名字,它假定那个名字不是一个类型,除非显式用typename关键字前置修饰该名字。

typename关键字有两个用途:

常见的在模板定义中的模板形参列表,表示一个模板参数是类型参数。等同于使用class。

使用模板类内定义的嵌套依赖类型名字时,显式指明这个名字是一个类型名。否则,这个名字会被理解为模板类的静态成员名。C++11起,这一用途也可以出现在模板以外,尽管此时typename关键字不是必要的。

在下述情形,对嵌套依赖类型名字不需要前置修饰typename关键字:

派生类声明的基类列表中的基类标识符;

成员初始化列表中的基类标识符;

用class、struct、enum等关键字开始的类型标识符

因为它们的上下文已经指出这些标识符就是作为类型的名字。

template关键字

template关键字有两个用途:

常见的在模板定义的开始。

模板类内部定义了模板成员函数或者嵌套的成员模板类。在模板中,当引用这样的模板成员函数或嵌套的成员模板类时,可以在::(作用域解析)运算符、.(以对象方式访问成员)运算符、->(以指针方式访问成员)运算符之后使用template关键字,随后才是模板成员函数名字或嵌套的成员模板类名字,这使得随后的左尖括号<被解释为模板参数列表的开始,而不是小于号运算符。C++11起,这一用途也可以出现在模板以外,尽管此时template关键字不是必要的。例如:

classA{public:templateclassB{public:typedefintINT;};templatevoidfoo(){}};templateintf(){typenameT::templateB::INTi;i=101;Ta,*p=&a;a.templatefoo();p->templatefoo();return0;}intmain(){f();A::B::INTi;// 自C++11起,也可写作typename A::template B::INT i;}

别名模板

别名模板(aliase template)是C++11引入的技术。在C++03标准中,可以用typedef给全特化模板定义新的类型名。但是不允许用typedef施加于偏特化模板上。例如:

templateclassSomeType;templatetypedefSomeTypeTypedefName;// Illegal in C++03

C++11增加了给偏特化模板增加别名的功能,例如:

templateclassSomeType;templateusingTypedefName=SomeType;

using在C++11中也可用于其他的类型别名的声明:

typedefvoid(*FunctionType)(double);// Old styleusingFunctionType1=void(*)(double);// New introduced syntax

模板实例化

模板实例化(template instantiation)是指在编译或链接时生成函数模板或类模板的具体实例源代码。ISO C++定义了两种模板实例化方法:隐式实例化(当使用实例化的模板时自动地在当前代码单元之前插入模板的实例化代码)、显式实例化(直接声明模板实例化)。在C++语言的不同实现中,模板编译模式(模板初始化的方法)大致可分为三种:

Borland模型(包含模板编译模式):编译器生成每个编译单元中遇到的所有的模板实例,并存放在相应的目标文件中;链接器合并相同的模板实例,生成可执行文件。为了在每次模板实例化时模板的定义都是可见的,模板的声明与定义放在同一个.件中。这种方法的优点是链接器只需要处理目标文件;这种方法的缺点是由于模板实例被重复编译,编译时间被加长了,而且不能使用系统的链接器,需重新设计链接器。

Cfront/查询模型(分离(Separation)模板编译模式):AT&T公司的C++编译器Cfront为解决模板实例化问题,增加了一个模板仓库,用以存放模板实例的代码并可被自动维护。当生成一个目标文件时,编译器把遇到的模板定义与当前可生成的模板实例存放到模板仓库中。链接时,链接器的包装程序(wrapper)首先调用编译器生成所有需要的且不在模板仓库中的模板实例。这种方法的优点是编译速度得到了优化,而且可以直接使用系统的链接器;这种方法的缺点是复杂度大大增加,更容易出错。使用这种模型的源程序通常把模板声明与非内联的模板成员分别放在.件与模板定义文件中,后者单独编译。

混合(迭代)模型:g++目前是基于Borland模型完成模板实例化。g++未来将实现混合模型的模板实例化,即编译器把编译单元中的模板定义与遇到的当前可实现的模板实例存放在相应的目标文件中;链接器的包装程序(wrapper)调用编译器生成所需的目前还没有实例化的模板实例;链接器合并所有相同的模板实例。使用这种模型的源程序通常把模板声明与非内联的模板成员分别放在.件与模板定义文件中,后者单独编译。

ISOC++标准规定,如果隐式实例化模板,则模板的成员函数一直到引用时才被实例化;如果显式实例化模板,则模板所有成员立即都被实例化,所以模板的声明与定义在此处都应该是可见的,而且在其它程序文本文件使用了这个模板实例时用编译器选项抑制模板隐式实例化,或者模板的定义部分是不可见的,或者使用template type FUN_NAME(type list)的语句声明模板的特化但不实例化。

g++的模板实例化,目前分为三种方式:

不指定任何特殊的编译器参数:按Borland模型写的源代码能正常完成模板实例化,但每个编译单元将包含所有它用到的模板实例,导致在大的程序中无法接受的代码冗余。需要用GNU的链接器删除各个目标文件中冗余的模板实例,不能使用操作系统提供的链接器。

使用-fno-implicit-templates编译选项:在生成目标文件时完全禁止隐式的模板实例化,所有模板实例都显式的写出来,可以存放在一个单独的源文件中;也可以存放在各个模板定义文件中。如果一个很大的源文件中使用了各个模板实例,这个源文件不用-fno-implicit-templates选项编译,就可以自动隐式的生成所需要的模板实例。在生成库文件时这个编译选项特别有用。

使用-frepo编译选项:在生成每个目标文件时,把需要用到的当前可生成的模板实例存放在相应的.rpo文件中。链接器包装程序(wrapper)—collect2将删除.rpo文件中冗余的模板实例并且修改相应的.rpo文件,使得编译器可以利用.rpo文件知道在那里正确放置、引用模板实例,并重新编译生成受影响的目标文件。由操作系统的通用的链接器生成可执行文件。这对Borland模型是很好的模板实例化方法。对于使用Cfront模型的软件,需要修改源代码,在模板头文件的末尾加上#include 。不过MinGW中不包含链接器包装程序collect2,故不使用此方法。对于库(library),建议使用显式实例化方法。

另外,g++扩展了ISOC++标准,用extern关键字指出模板实例在其它编译单元中显式声明(这已经被C++11标准接受);用inline关键字实例化编译器支持的数据(如类的虚表)但不实例化模板成员;用static关键字实例化模板的静态数据成员但不实例化其它非静态的模板成员。

g++不支持模板实例化的export关键字(此关键字的这个用法已在C++11标准里被取消)。

VC++7.0中必须类模板实例化只有Borland模型;函数模板一般隐式实例化,自5.0版以后也可显式实例化。



免责声明:以上内容版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。感谢每一位辛勤著写的作者,感谢每一位的分享。

——— 没有了 ———
编辑:阿族小谱
发表评论
写好了,提交
{{item.label}}
{{commentTotal}}条评论
{{item.userName}}
发布时间:{{item.time}}
{{item.content}}
回复
举报
点击加载更多
打赏作者
“感谢您的打赏,我会更努力的创作”
— 请选择您要打赏的金额 —
{{item.label}}
{{item.label}}
打赏成功!
“感谢您的打赏,我会更努力的创作”
返回

更多文章

更多精彩文章
打赏
私信

推荐阅读

· 模板元编程
模板元编程的构成要素使用模板作为元编程的技术需要两阶段的操作。首先,模板必须被定义;第二,定义的模板必须被实体化才行。模板的定义描述了生成源码的一般形式,而使实体化则导致了某些源码的组合根据该模板而生成。模板元编程是一般性地图灵完全(Turing-complete),这意味着任何可被电算软件表示的运算都可以通过模板元编程以某种形式去运算。模板与宏(macros)是不同的。所谓宏只不过是以文字的操作及替换来生成代码,虽然同为编译期的语言特色,但宏系统通常其编译期处理流的能力(compile-timeprocessflowabilities)有限,且对其所依附之语言的语义及类型系统缺乏认知(一个例外是LISP的宏)。模板元编程没有可变的变量——也就是说,变量一旦初始化后就不能够改动。因此他可以被视为函数式编程(functionalprogramming)的一种形式。使用模板元编程模板元编程的语...
· 远古海底世界的模板(五)
野外回来后对采集到的标本进行检查,发现了更多很有价值的硫铁矿矿石结构特征,但仍然没有确认找到黑烟囱。于是把那些类黑烟囱标本切开,一看其内部具有现代海底黑烟囱描述的良好结晶颗粒和分层特征。通过进一步的观测和对比研究后,研究组确信找到了14亿年前的海底黑烟囱。
· 远古海底世界的模板(四)
海洋,地球资源的大宝藏,在陆地资源日益枯竭的今天,将越来越成为人类未来生产和生活的依靠。从海洋中引发的许多问题和思考,还促进了科学理论和技术的不断向前发展,如板块构造理论,就是在对海洋的研究中不断完善和发展起来的。自20世纪中期以来,大规模的海洋调查如大洋钻探计划的开展,深海观测技术如深潜器的应用,使得人类对海洋的研究无论从深度还是广度上,都得到了长足的进步。现代海底黑烟囱及其热液矿藏的发现,就是全球海洋地质调查近十年中取得的最重要的科学成就。海底黑烟囱的发现现代海底黑烟囱的研究开始于1977年,美国的阿尔文(Alrin)号载人深潜器上的地质学家在东太平洋洋中脊(北纬21°)地区发现了深海的生物世界,1978年又在洋中脊的轴部首次采得了由黄铁矿、闪锌矿和黄铜矿组成的硫化物。1979年又在同一地点约1650~2610米深的海底熔岩上,发现了数十个冒着黑色和白色烟雾的烟筒,以及附近由铜、铁、锌...
· 远古海底世界的模板(二)
海洋,地球资源的大宝藏,在陆地资源日益枯竭的今天,将越来越成为人类未来生产和生活的依靠。从海洋中引发的许多问题和思考,还促进了科学理论和技术的不断向前发展,如板块构造理论,就是在对海洋的研究中不断完善和发展起来的。自20世纪中期以来,大规模的海洋调查如大洋钻探计划的开展,深海观测技术如深潜器的应用,使得人类对海洋的研究无论从深度还是广度上,都得到了长足的进步。
· 微信朋友圈讣告范文模板10篇
在人生旅途中,难免会遇到哀伤的时刻,当亲人或朋友离世,如何在朋友圈表达这份沉痛之情,显得尤为重要。恰当的文字不仅是对逝者的尊重,也是对生者慰藉的一种方式。今天,祭拜网小编整理了10篇简洁明了的微信朋友圈讣告模板,希望能帮到在悲痛中寻找安慰的你。模板一:讣告今日,我们怀着无比悲痛的心情,告知大家,我们的挚爱(逝者姓名)于(日期)安详离世。愿逝者安息,生者坚强。(讣告发布人、单位)(日期)模板二:讣告(逝者姓名),您那慈祥的笑容和温暖的话语永远留在我们心中。(日期),您悄然离去,愿天堂没有痛苦,只有宁静。(讣告发布人、单位)(日期)模板三:讣告我们以沉重的心情宣布,(逝者姓名)于(日期)与世长辞。他的音容笑貌将永远铭记在我们心中。愿天堂之路光明。(讣告发布人、单位)(日期)模板四:讣告尊敬的朋友们,我们敬爱的(逝者姓名)在(日期)结束了他的人生旅程。我们将永远怀念他的一切美好。(讣告发布人、单...

关于我们

关注族谱网 微信公众号,每日及时查看相关推荐,订阅互动等。

APP下载

下载族谱APP 微信公众号,每日及时查看
扫一扫添加客服微信