不论是生活中还是编程中,我们都想要一种通用的方法去解决一类问题。但所有的方法都有它的优点和缺点。
在C语言学习中,C语言提供了一种泛型机制,通过传入无类型的参数,和数据大小来解决一类问题。但这种方式没有足够的类型检查,很容易出错。
这时候你是否想到了函数重载,将不同参数的函数都写出来,这样虽然能够起到一定的作用,但是太过复杂,而且容易没有全部写出来。
我们也可以使用宏定义函数,但宏函数毕竟不是函数,它在预编译期间处理,没有安全检查。
所以C++为了得到一种更好的方法来解决这个问题,引入了模板的概念。
模板:C++的泛型机制
其中X是一个虚拟类型,参数列表和函数参数列表差不多。<>中可包含许多参数。
函数模板:
1、怎样编译:
分两部分编译:
1、定义点编译模板头部
2、调用点编译模板的模板体(也就是说函数模板是在调用点生成函数,这个过程称作模板的实例化)
2、模板的实参推演:
1、当调用点没有指明参数类型时,系统会自动的进行实参推演,这个过程是一个精确匹配的过程,不能产生二义性。
2、需要有参数类型,不然无法进行实参推演。
#include<iostream>
using namespace std;
template<typename X>
X Show(X a)
{
cout << a << endl;
return a;
}
int main()
{
Show(10);
return 0;
}
3、模板特例化
虽然函数模板可以解决不同参数的问题,但是有时候我们需要添加模板特例化来满足我们的需求。
比如比较大小的函数,一般的int char double float类型都可以用模板实现,但字符串比较大小就需要特例化版本来实现比较大小了。
模板的特例化是特殊的模板实例化,是自己写出来的针对某个特殊需求的模板实例化。
template<typename Z>
bool Compare(Z a , Z b)
{
cout << "实例化模板" << endl;
return a > b;
}
template<>
bool Compare(char *a ,char *b)
{
cout << "特例化模板" << endl;
return strcmp(a , b) > 0;
}
特例化不需要模板参数。
5、函数模板的重载
bool Compare(char *a ,char*b)
{
cout << "普通函数" << endl;
return strcmp( a , b) > 0;
}
template<typename Z>
bool Compare(Z a , Z b)
{
cout << "实例化模板" << endl;
return a > b;
}
template<>
bool Compare(char *a ,char *b)
{
cout << "特例化模板" << endl;
return strcmp(a , b) > 0;
}
普通函数版本、模板实例化版本、模板特例化版本构成了模板重载。
如果调用点的函数出现<>符号,那么表明调用的是模板
如果未作标识,会调用普通函数版本。
普通函数版本 > 模板特例化版本 > 模板实例化版本(优先级顺序)。
6、模板的参数列表
1、类型参数 :一般的虚拟类型
2、非类型参数 :1、是一个常量 2、不允许使用double或foalt类型的数据
#include<iostream>
using namespace std;
template<typename T, int SIZE>
void Print(T* arr)
{
for (int i = 0; i < SIZE; ++i)
{
cout << arr[i] << " ";
}
cout << endl;
}
int main()
{
int arr[] = {15,71,54,45,4,5,3,46};
Print<int,sizeof(arr)/sizeof(arr[0])>(arr);
return 0;
}
7、 模板的默认值:
函数模板的默认值是C++ 11的特性
它的用法和函数的默认值用法相同。
8、系统自己进行实参推演的过程称为隐士实例化。
我们以可以自己写出模板的显式实例化。
显示实例化 关键字template + 函数(返回值、形参都给定类型。)
9、auto关键字
自适应的调节类型。
template<typename T> //模板 T是一个虚拟类型
T Sum(T a ,T b)
{
cout << "Sum(T a,T b)" << endl;
return a + b;
}
int main()
{
auto a = Sum(10,20); //auto自适应的调节类型
cout << "a::"<< a << endl;
}