在C++中可以写一些函数模板例如:(我们可以使用typename/class定义类型参数,可以定义多个类型参数。)
template<typename T>
bool compare(T a,T b)
{
cout<<"template compare"<<endl;
return a>b;
}
这个就是一个函数模板,编译器不对函数模板进行编译,因为编译器无法生成相应的符号(因为函数模板的类型是T,T还不知道是那个具体的类型)。在函数的调用处(知道了函数模板中T的类型我们便可以实例化),那么编译器用用户指定的类型,从原模板实例化一份代码出来生成相应的函数。
调用的时候我们一般使用<>指定T的类型例如
compare<int>(10, 20);//模板名加参数列表才是函数名
compare<double>(10.0, 20.0);
当然我们也可以直接调用:这里存在模板的实参推演过程:编译器根据用户传入实参类型推演函数。即下例:
compare(10,20);
模板存在的意义:我们只需要注重于功能的实现,我们不用过多的注重参数类型。
模板函数(函数模板有了具体的类型后)才是要被编译器编译的。
但是有的时候依靠函数模板的默认逻辑处理有些变量或者对象是错误的
例如上例中的我们使用
compare("aa","bb");
实例化出来的函数是
bool compare(const char*a, const char *b)
{
return a>b
}
这很显然是不对的。
针对compare 函数模板,提供const char *类型的特例化版本
template<>
bool compare<const char*>(const char*a,const char*b)
{
return strcmp(a,b)>0;
}
我们使用这个就可以根据不同的类型特例化某个函数模板。
我们看如下代码
#include <iostream>
using namespace std;
//函数模板
template<typename T> //定义一个模板参数列表
bool compare(T a, T b)//compare是一个函数的模板
{
cout << "template compare" << endl;
return a > b;
}
//函数模板特例化
template<>
bool compare<const char*>(const char*a, const char*b)
{
cout << "compare<const char*>(const char*,const char*)" << endl;
return strcmp(a, b) > 0;
}
//普通函数
bool compare(const char *a, const char *b)
{
cout << "compare(const char*,const char *)" << endl;
return strcmp(a, b) > 0;
}
int main()
{
compare("aa","bb");
return 0;
}
入上代码中我们文件中存在三个compare函数,一个时模板函数,一个是模板函数的特例化,一个是不同的函数。(这种现象称为共存现象)
我们在主函数中调用compare时,默认编译器调用的是普通函数,因为编译器默认做的事情越少越好,所以它直接默认调用的就是普通函数。也可以说成编译器优先把函数compare处理成函数名字,没有的话在去找compare模板。
我们日常项目中默认使用function.h中对函数声明,在function.cpp中对函数定义。
那么我们的模板函数也可以这样码?
我们看下例子:
//test.cpp
#include <iostream>
using namespace std;
//函数模板
template<typename T> //定义一个模板参数列表
bool compare(T a, T b)//compare是一个函数的模板
{
cout << "template compare" << endl;
return a > b;
}
//函数模板特例化
template<>
bool compare<const char*>(const char*a, const char*b)
{
cout << "compare<const char*>(const char*,const char*)" << endl;
return strcmp(a, b) > 0;
}
//普通函数
bool compare(const char *a, const char *b)
{
cout << "compare(const char*,const char *)" << endl;
return strcmp(a, b) > 0;
}
//main.cpp
#include <iostream>
using namespace std;
template<typename T>
bool compare(T a,T b);
int main()
{
compare(10,20);
return 0;
}
编译项目
出现如图所示的链接错误:产生这个原因是因为,模板函数只有在调用的时候才对它进行实例化,函数模板本生不参与编译。所以在链接的时期,main.cpp找不到函数的段无法合并导致的链接错误。
解决办法:
我们可以直接在模板函数的实现模板函数的实例化
例如在test.cpp加入以下代码
//告诉编译器实例化
template bool compare<int>(int, int);
template bool compare<double>(double, double);
但是这不是一个一劳永逸的办法,因为作为开发者,我们无法去实例化所有的类型。
所以我们一般采用第二种办法
就是将模板函数的实现和声明写在同一个.h文件中,哪里要用函数模板,直接引入头文件即可。