函数模板:
template
bool compare(T a, T b)
{
return a > b;
}
我们看这段代码,compare是一个函数名还是一个模板名?其实他是一个模板名。如果要把它看成一个函数来使用,就要用一个类型来实例化这个模板,在使用时可以给其后尖括号中加上要使用的类型名如下:
int main()
{
compare(10, 20);
return 0;
}
用int类型给模板传参的过程叫做模板的实例化。模板的实例化(显式实例化/隐式实例化),上面讲到的那个实例化是隐式实例化,我们只是指出了我们实参的类型,并没有显示的定义我们要实例化的模板函数,其他的工作都是系统帮我们完成的。
隐式实例化:在系统执行到上面主函数中代码时,系统会自动调用模板函数生成一份整形参数的compare函数
bool compare(int a, int b)
{
return a > b;
}
系统编译链接的其实就是这段代码。函数模板不能编译,而是在调用点实例化一个所指定类型参数的模板函数去调用。
函数模板->实例化->模板函数。也就是说模板并没有省略系统要编译的代码。只是把这些代码让系统通过我们定义的模板自己完成编写。没有明确给出我们要实例化的参数类型的模板函数声明,而是直接在调用时用模板名加尖括号中包含类型的这种方式叫做隐式实例化。而明确声明了我们要实例化的参数类型并给出了其函数声明这种情况被称为显式实例化。
template bool compare(double, double);
template bool compare(float, float);
int main()
{
compare(10,20);
return 0;
}
模板类型参数:可以用class或者typename来定义,建议使用typename以防止参数被误认为是一个类,一般情况下参数都用大写。可以定义多个参数。模板的非类型参数:我们知道模板的类型参数只能用class或者typename来定义,因此用除此之外其他的东西来定义的模板参数就是模板的非类型参数,模板的非类型参数一般都是写成大写。
typename
bool compare(T a, T b)
{
return a > b;
}
模板的实参推演:我们看下面这个例子,之前说过,模板必须实例化之后才能使用,可是下面这个明显是直接调用模板名的,为什么也能得出正确答案呢?在我们调用模板时,理应指出其实参的类型,如果没有指出实参类型的话,系统就会自动进行模板的实参推演.
template
bool compare(T a, T b)
{
return a > b;
}
int main()
{
compare(10, 20);
}
这里就是我们要说的模板的实参推演。在直接使用模板的时候,如果该函数模板有形参,并且使用处给出了可推导其类型的实参c++模板类,(实参的个数和给出的函数模板中模板参数个数一致,实参的可推导类型必须和模板参数一致,)这时候模板就会进行实参推演,推出其实参的类型,并实例化一个该类型的模板函数。也就是说,这里其实还是调用了模板函数(系统通过模板的实参推演自动实例化该类型的模板函数),而不是直接使用模板。下面是推演失败的例子:
template
bool compare(T a, T b)
{
return a > b;
}
int main()
{
compare(10,20,30);
compare(10, 12.5);
}
推演的成功与否和我们模板的定义有关,如果我们所定义的函数模板有两个不同的模板参数,这个时候下面这种情况就是允许的,当我们定义两个不同字符表示的模板参数时,模板的实参推演就会变得更加广泛
template
bool compare(T a, E b)
{
return a > b;
}
int main()
{
compare(10,20);
compare(10,12.5);
}
模板的特例化(专用化):
上面说了在我们没有表明我们的实参类型时,模板可以进行实参推演,当我们实参输入的是两个字符串常量时,模板推演出来的实参类型是const char *,而这时,如果我们继续使用我们上面的这个通用的函数模板,显然以这样的方式比较两个字符串常量的大小是错误的。这时我们必须给出专门用来比较两个字符串大小的特例化的模板函数,也就是模板的特例化。模板特例化的时候,不用再在尖括号里面声明模板参数,只用给出关键字template和尖括号即可。而函数体的尖括号中的类型也不再是模板参数T,而是我们所要特例化的确定的类型。
//模板的特例化
template
bool compare(const char* a, const char* b)
{
return strcmp(a, b) > 0 ? true :false;
}
注意:函数模板不支持部分特例化,类模板支持。
模板的编译:我们把模板的定义和使用放在两个不同的文件中,会发现在编译链接时出现了链接错误(无法解析的外部符号)这是因为模板本身是不参加编译链接过程的,只有它实例化的模板函数才会进行编译和连接,不进行编译链接就没有任何的实例化,而实例化是在编译过程进行的,编译时各个cpp文件都是单独编译,因此单独在一个cpp文件中的模板定义也就不会产生符号,那么另外一个文件中使用它时自然不会找到它的定义之处c++模板类,因此就会出现链接错误.一般情况下,模板的定义都会写在头文件中,应用时直接包含头文件即可
模板函数的重载:非模板函数,模板的特例化,函数模板三者可以共存
模板的执行顺序:非模板函数——》模板的特例化——》函数模板
限时特惠:本站每日持续更新海量设计资源,一年会员只需29.9元,全站资源免费下载
站长微信:ziyuanshu688