模版函数
我们知道,使用c++时必须对数据进行数据类型的定义,但是有时候这种类型的定义会显得不必要且繁琐,比如
bool bigger(const int& a,const int& b)
{
return a>b;
}
bool bigger(const double& a,const double& b)
{
return a>b;
}
观察上述代码,我们要实现的是比较两个参数a和b的大小,而对于参数a参数b,由于不同的数据类型,因此我们需要重载两个数据类型的函数以满足不同的需要
那么,有没有一种办法,可以让形参的类型也可以参数化呢?这就是模版函数的作用
template<typename T>
bool bigger(const T& a,const T& b)
{
return a>b;
}
再次观看以上代码,我们首先定义了一个模版类型参数T,这个T代表了某个类型
当我们在调用bigger函数的时候,我们可以显示指定T,当然也可以不指定,让编译器进行自动推导
如下是显示指定T的方式
bigger<int>(1,2);//显示指定T,T此时为int
bigger<double>(2.5,1);//显示指定T,T此时为double,此时尽管实参b是一个int,也会被强制转换为double
如下是隐式推断
bigger(1,2);//T此时被推断为int
bigger(1.5,2.5);//T此时被推断为double
bigger(1.5,2);//编译器推断失败,将会报错,此时必须使用显示指定T的类型进行类型转换调用
可以看到,无论是显示指定还是隐式推断,对于同样功能的函数,此时我们只需要声明一份函数即可,而无需重复写多个函数的重载。
但需要注意的是,我们没有对函数进行重载,但并不代表编译器没有对函数进行重载。事实上,当我们在对模版函数进行调用的时候,编译器会对我们的代码进行实例化,也就是说
bigger<int>(1,2);
当我们的代码执行的这里时,编译器会为我们实例化一份对应的函数代码
bool bigger(const int& a,const int& b)
{
return a>b;
}
同理,当我们执行以下代码时
bigger<double>(1,2);
编译器同样会为我们实例化一份这样一份代码
bool bigger(const double& a,const double& b)
{
return a>b;
}
模版函数的特例化
为了说明问题,我们直接看以下代码
#include<iostream>
template<typename T>
bool bigger(const T& a,const T& b)
{
return a>b;
}
int main()
{
std::string a="b";
std::string b="ab";
// bool res=bigger<double>(3.5,2);
bool res=bigger(a,b);
if(res)
std::cout<<"a is bigger than b"<<std::endl;
else
std::cout<<"a is less than b"<<std::endl;
return 0;
}
我们同样定义了一份模版函数,但是我们此时定义了两个std::string类型的参数,我们想实现的是,可以比较两个string类型的参数的字符串长度
可以看到,当我们编译运行后发现,程序的运行结果与我们的想法背道而驰了
先说为什么会出现这样的结果
首先我们知道参数a是"b",参数b是"ab",如果我们直接比较"b"和"ab"的大小,实际上比较的是这两个字符串的首地址大小,显然"b"的首地址b是大于"ab"的首地址a的
特殊情况就要特殊处理,因此出现了所谓的模版特例化
#include<iostream>
template<typename T>
bool bigger(const T& a,const T& b)
{
return a>b;
}
template<>
bool bigger(const std::string& a,const std::string& b)
{
std::cout<<">>>";
return a.length()>b.length();
}
int main()
{
std::string a="b";
std::string b="ab";
// bool res=bigger<double>(3.5,2);
bool res=bigger(a,b);
if(res)
std::cout<<"a is bigger than b"<<std::endl;
else
std::cout<<"a is less than b"<<std::endl;
return 0;
}
再看上述代码,我们定义了在原来的模版函数的基础上,又定义了一份代码
template<>
bool bigger(const std::string& a,const std::string& b)
{
std::cout<<">>>";
return a.length()>b.length();
}
这个就是模版特例化的代码,针对参数类型T为std::string所声明的特例化,注意这并不是函数重载
再次编译运行
可以看到,此时代码成功调用的是特例化的代码