模板小结

模板

前天看了primer有关类的继承的内容,并做了一些笔记,昨天和今天看了C++里面的泛型编程的模板,现在也来总结一下吧。

一、定义

模板定义:模板就是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数, 从而实现了真正的代码可重用性。模版可以分为两类,一个是函数模版,另外一个是类模版。

在C++中,模板是泛型编程的基础,模板是创建类或函数的蓝图或公式。模板定义为以关键字template开始,后接模板形参表,模板形参表用尖括号挺住的一个或多个模板形参的列表,形参之间以逗号分隔。模板形参表不能为空。例如:

Template int fun(const T &v1, const T &v2);

1、模板形参。模板形参表示可以在类或函数的定义中使用的类型或值,模板形参可以是表示类型的类型形参,也可以是表示常量表达式的非类型形参,类型形参跟在关键字class或typename之后定义,class和typename没有区别;类型形参表示未知类型,非类型形参表示是一个未知值。

通过在成员名前面加上关键字typename作为前缀,可以告诉编程器将成员当作类型,例如typename test::size_type,则size_type是一种类型,而不是一个值。

在调用函数时非类型形参将用值代替,值的类型在模板形参表中指定。模板非类型形参是模板内部定义的常量值,对于模板的非类型形参而言,求值结果相同的表达式将认为是等价的。

2、模板实例化。使用函数模板时,编译器会推断哪个模板实参绑定到模板形参。一旦编译器确定了实际的模板实参,就称它实例化了函数模板的一个实例。只有在调用时,模板才会实例化。

3、使用模板形参名字的限制。模板形参的名字只能在同一模板形参表中使用一次。每个模板类型形参前面必须带上关键字class或typename,每个非类型形参前面必须带上类型名字。

二、实例化

1、实例化。模板在使用时将进行实例化,类模板在引用实际模板类类型进实例化,函数模板在调用它或用它对函数指针进行初始化或赋值时实例化。

2、类的实例化。类模板的形参是必需的,想有使用类模板,就必须显式 指定模板实参。用模板类定义的类型总是包含模板实参。例如:

test t;//error

test t;//ok

test 不是类型,test是类型

3、函数模板实例化。实例化是进行模板实参推断(从函数实参确定模板实参的类型和值的过程),多个类型形参必须完全匹配。也不会转换实参以匹配已有的实例,而是会产生新的实例,但有两种例外的情况,const转换和数组或函数到指针的转换。注意,当形参为引用时,数组不能转换为指针。

4、编译器使用指针的类型实例化具有适当模板实参的模板版本。形参的类型决定了T的模板实参的类型。

5、模板编译模型。模板编译模型包括:包含编译模型和分别编译模型两种,大多数编译器都支持包含编译模型,只有一些编译器支持分别编译模型。包含编译模型会产生多个实例,并在预链接阶段或链接阶段选择一个实例化而丢弃其他 。头文件中的类定义体不应该使用关键字export.

三、类模板成员

1、通常当使用类模板的名字的时候,必须指定模板形参。这一规则有个例外:在类本身的作用域内部,可以使用类模板的非限定名。例如,test是test的缩写表示。而且编译器不会为类中使用的其他模板的模板形参进行推断,在声明类类型成员时,必须指定类型形参。

2、类模板成员函数。类模板的成员函数本身也是函数模板,与其他函数模板不同的是,在实例化类模板成员函数的时候,编译器不执行模板实参推断,相反,类模板成员函数的模板形参由调用该函数的对象的类型确定。类模板成员函数只有为程序所用才进行实例化,类模板的指针定义不会对类进行实例化,只有用到这样的指针时才会对类进行实例化。在类外定义时,要注明是函数模板,例如,template void test::fun(){};

3、类模板中的友元关系。

*普通友元,非模板类或非模板函数是类模板的友元,该友元可以访问模板类的任意实例的成员。即一对多的关系。

*一般模板友元关系,模板类或模板函数是类模板的友元,该友元的任意实例实例可以访问模板类的任意实例的成员。即多对多的关系。

*特定的模板友元关系,只授予特定实例的模板类或模板函数为类模板的友元,只有该友元的特定实例可以访问模板类的实例,即一对一的关系或一对多的关系,取决于该友元的模板形参是否与模板类的模板形参相同,相同则是一对一的关系,不同则是一对多的关系。

四、模板特例化

1、简单点来说,模板特例化就是为了让模板更“泛”,能够应用于更多的情况。

2、函数模板的特化;定义中一个或多个模板形参的实际类型或实际值是指定的

形式:

*关键字template后面接一对空的尖括号<>;

*再接模板名和一对尖括号,尖括号中指定这个特化定义的模板形参;

*函数形参表

*函数体

例如:template<> int fun (const char * const &v)

在模板物化版本的调用中,实参类型必须与特化版本函数的形参类型完全匹配,普通作用域规则适用于特化。

3、类模板的特化

例如:template<> class test{};

除了特化整个模板类之外,还可以只特化类中的成员。

类模板的特例化,还可以是类模板的部分特化,这种定义以关键字template开头,接着是由尖括号<>括住形参表,部分特化的模板形参表只列出未知模板实参的那些形参。

个人觉得所有的特例化的尖括号〈〉都可以理解为括住未知的模板形参,前面所述的是因为没有未知的模板形参,所以尖括号为空。

五、重载与函数模板

1、如果调用有二义性,从可行函数集合中去掉所有函数模板实例。

2、设计一组重载的函数模板,其中一些是模板而另一些是普通函数,这是困难的。






原文链接: https://www.cnblogs.com/ljianhui/archive/2012/07/15/2695919.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/55362

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 上午6:29
下一篇 2023年2月9日 上午6:29

相关推荐