C++模板小结【转载】

一、定义

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

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

Template <typename T> 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<int> t;//ok

test 不是类型,test<int>是类型

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

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

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

三、类模板成员

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

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

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

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

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

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

四、模板特例化

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

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

    形式:

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

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

*函数形参表

*函数体

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

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

    3、类模板的特化

    例如:template<> class test<const char*>{};

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

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

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

五、重载与函数模板

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

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

原文地址:https://www.cnblogs.com/DragonX/p/3526016.html