1、C++ 函数模板
1.1、函数模板定义
模板的意义: 对类型也可以进行参数化了
可以定义多个类型参数,中间用逗号隔开 也可以用关键字class替代typename
1.2、函数模板调用
我们看下面代码:
compare只是一个函数模板名称。我们调用这个compare的时候,肯定是希望这个是模板函数名称。 模板名加上参数列表才是函数名称
在调用点,编译器又会用double去实例化一份函数代码出来模板函数如下 模板的好处:
- 我们用户只用写一套代码实现逻辑就可以了,至于用什么类型,模板最终用什么类型实例化,我们可以在调用的地方去指定类型,编译器就会从原模板用指定的类型去实例化代码出来。
- 对于编译器来说,需要待编译的函数并没有减少,每个类型都对应一份函数。
只用函数模板的名字,我们也可以进行函数的调用 因为 模板的实参推演 => 可以根据用户传入的实参的类型,来推导出模板类型参数的具体类型
注意:
- 不会再生成和之前生成的模板函数一模一样的函数,不然就成函数的重定义了,会产生符号,每个模板函数的符号只能出现一次,每种模板函数只产生一份,下次需要调用就直接调用之前产生的那个对应的模板函数就可以了
- 某个类型实例化的函数只会产生一次
下面这种情况是什么样的?
通过第一个传入的实参,推导出T是int整型,通过第二个传入的实参,推导出T是double型,那么T到底是int还是double呢??? 编译器推导不出来。
- 另外定义一个新的模板类型参数,a和b用不同的模板类型参数。
- 我们还可以指定模板类型是int,第一个实参是整型,就传给整型,第二个实参是double,就把double转换成int整型带进去。
函数模板是无法编译的。 因为不知道T的类型是什么,无法编译。
- 函数模板 =》是不进行编译的,因为类型还不知道
- 模板的实例化 =》函数调用点进行实例化,实例化的模板函数,才是要被编译器所编译的
模板函数:
1.3、模板偏特化
假设现在我们要比较两个字符串: 也是可以比较的
- 但是,我们在调用这个模板的时候,并没有指定这个参数列表,它就得进行函数模板实参的推演,通过实参推导出T是
const char*
得到的实例化的模板函数是:
- 显然这是在比较两个字符串的地址的大小,没有意义啊。
- 我们肯定是想比较它们的字典顺序。
实际上,应该调用:
- 但是编译器没有办法,因为模板给的是a>b,它只能用你指定的或者推导出来的类型来确定类型,并不能根据具体的类型来改变你的代码。
遇到的问题: 对于某些类型来说,依赖编译器默认实例化的模板代码,代码处理逻辑是有错误的
怎么办?
- 我们需要给模板提供特例化了。
- 模板的特例化(专用化) 特殊(不是编译器提供的,而是用户提供的)的实例化
- 先有模板,才能模板特例化哦
再写一个普通函数: 此时是调用 普通非模板函数?还是调用模板特例化函数?
调用普通非模板函数!
如果写成这样,编译器不会将compare当成函数名! 因为函数名后面不可能 + <> 符号的,只有模板名后面才能 + <>!
调用特例化的模板函数!
compare("aaa", "bbb");
compare<const char*>("aaa", "bbb");
我们再看,我们在写多文件的时候,要注意:
- 我们在一个文件中定义模板,在另一个文件中声明模板,然后使用它。
- 会发生链接错误
C++模板.cpp 运行结果:
- 出现链接错误!
没有找到compare的int和double类型的。
但是下面这两个找到了,因为一个是普通函数,一个是模板的特例化 测试:
- 将上面的屏蔽掉,只留最后两个,同时在文件中声明普通函数和模板的特例化函数:
在链接的时候,找下在其他文件定义的地方,可以找到!!!
**问题:**为什么int和double的找不到?
- 模板本身是不编译的,类型不知道;
- 调用的时候才会进行编译!!
生成并编译下面的模板函数:
- 模板代码是不能在一个文件中定义,在另外一个文件中使用的
- 模板代码调用之前,一定要看到模板定义的地方,这样的话,模板才能够进行正常的实例化,产生能够被编译器编译的代码
- 所以,模板代码都是放在头文件当中的,然后在源文件当中直接进行#include包含(例如STL库中的)
- include是在预编译的过程中,把头文件的代码直接在当前源文件中展开
如果一定要在多个文件调用,还是有办法的。 不用看调用点,直接用用户指定的类型进行模板实例化。
1.4、模板的非类型参数
- 必须是整数类型(整数,其他类型的指针地址/引用都可以)
- 都是常量,只能使用,而不能修改
#include <iostream>
using namespace std;
template<typename T, int SIZE>
void sort(T* arr)
{
for (int i = 0; i < SIZE - 1; ++i)
{
for (int j = 0; j < SIZE - 1 - i; ++j)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
int main()
{
int arr[] = { 12,5,7,89,32,21,35 };
const int size = sizeof(arr) / sizeof(arr[0]);
sort<int, size>(arr);
for (int val : arr)
{
cout << val << " ";
}
cout << endl;
return 0;
}
这两个是等价的!
|