模板与泛型编程之定义模板

函数模板

template <typename T>//模板参数列表
int compare(const T &v1,const T &v1)//模板参数
{
    if(v1return -1;
    if(v2return 1;
    return 0;
}

当我们调用一个函数模板时,编译器用函数实参来为我们推断模板实参。

cout<1,0);//实例化为int compare(const int&,const &int)

模板类型参数
前面必须加关键字class或typename。可以用来指定返回类型或函数的参数类型,也可早函数体内用于变量声明或类型转换。

template T> T foo(T* P)//返回类型T,参数类型T*
{
    T tmp=*p;
    //...
    return tmp;
}

非类型模板参数:
表示一个值(实参必须是常量表达式)而非一个类型,通过一个特定的类型名来指定。

template<unsigned N,unsigned M>
int compare(const char (&p1)[N],const char (&p2)[M])
{
    return strcmp(p1,p2);
}

函数模板可以声明为inline或constexpr,关键字放在模板参数列表之后,返回类型之前。

template<typename T, unsigned size>
constexpr unsigned getSize(const T(&)[size])
{
    return size;
}

泛型代码的两个重要的原则:
(1)模板中的函数参数是const的引用。
(2)函数体中的条件判断仅使用<比较运算。

模板程序应该尽量减少对实参类型的要求。

函数模板和类模板成员函数的定义通常放在头文件中。


类模板:
编译器不能为类模板推断模板参数类型。我们必须在模板名后的尖括号提供额外信息–用来代替模板参数的模板实参列表。

模板与泛型编程之定义模板_第1张图片


一个类模板的每个实例都形成一个独立的类。类型Blob《string》与任何其他Blob类型都没有关联,也不会对任何其他 Blob类型的成员有特殊访问权限


类模板的成员函数:
与其他类相同,类模板成员函数既可以在类模板内部,也可以在类模板外部为其定义成员函数,且定义在类模板内的成员函数被隐式声明为内联函数。当我们在类外定义一个成员时,必须说明成员属于哪个类。而且,从一个模板生成的类的名字中必须包含模板参数。

模板与泛型编程之定义模板_第2张图片

默认情况下,对于一个实例化了的类模板,其成员只有在使用时才被实例化。

当我们在类模板自己的作用域中,我们可以直接使用模板名而不提供模板实参。(划线等于BlobPtr《T》)

模板与泛型编程之定义模板_第3张图片


类模板与友元:

(1)如果一类模板包含一个非模板友元,则友元可以访问所有模板实例。

(2)如果友元自身是模板,类可以授权给所有友元模板实例,也可以只授权给特定实例。

为了引用(类或函数)模板的一个特定实例,我们必须首先声明模板自身。一个模板声明包括模板参数列表:

模板与泛型编程之定义模板_第4张图片


一类可以将另一个模板的每个实例都声明为自己的友元,或者限定特定的实例为友元。

模板与泛型编程之定义模板_第5张图片

在新标准中,我们可以将模板类型参数声明为友元:

模板与泛型编程之定义模板_第6张图片


模板类型别名

这里写图片描述

模板与泛型编程之定义模板_第7张图片


模板参数:

模板参数会隐藏外层作用域中声明的相同名字,但是在模板内,不能重用模板参数名。

typedef double A;
template <typename A,typename B> void f(A a,B b)
{
    A tmp=a;//tmp的类型为模板参数A的类型,而非double
    double B;//错误,重声明模板参数B
}

模板声明必须包含模板参数。一个特定文件所需要的所有模板声明通常一起放置在文件开始位置,出现在任何使用这些模板的代码之前。

当我们希望通知编译器一个名字表示类型时,必须使用关键字typename,而不能使用class.


我们可以给模板提供默认模板实参。

模板与泛型编程之定义模板_第8张图片

无论何时使用一个类模板,我们必须在模板名之后接上尖括号。如果一个类模板为其所有模板参数都提供了默认实参,且我们希望使用这些默认实参,就必须在模板名之后跟一个空尖括号对。

template int> class numbers
{
public:
    numbers(T v=0):val(v){}
private:
    T val;
};
numbers <long double> lots_of_precision;
numbers <> average_precision;//空<>表示我们希望使用默认类型

成员模板:
一个类可以包含本身是模板的成员函数,这种成员称为成员模板。成员模板不能是虚函数。

普通类的成员模板:
模板与泛型编程之定义模板_第9张图片

模板与泛型编程之定义模板_第10张图片

类模板的成员模板:

template <typename T>//类的类型参数
template <typename It> //构造函数的类型参数
    Blob::Blob(It b,It e):
        data(std::make_shared<std::vector>(b,e)){}

实例化:

模板与泛型编程之定义模板_第11张图片


控制实例化:

当模板被使用时才会进行实例化这一特性意味着,相同的实例可能出现在多个对象文件中。为避免这种额外开销,我们可以通过显式实例化

形式:

extern template declaration;//实例化声明
template declaration;//实例化定义

例子:

模板与泛型编程之定义模板_第12张图片

在一个类模板的实例化定义中,所用类型必须用于模板的所有成员函数。


你可能感兴趣的:(C++)