文章目录
一、详解函数模板
模板的意义:对类型也可以进行参数化了
cpp
// 也可以用template<class T>,但class容易和类混淆,我们都用typename
template<typename T> // 模板参数列表
bool compare(T a, T b) // compare是一个函数模板
{
cout << "template compare" << endl;
return a > b;
}
/*
调用点实例化出来的模板函数
bool compare<int>(int a, int b)
{
return a > b;
}
bool compare<double>(double a, double b)
{
return a > b;
}
*/
int main()
{
// 函数的调用点
compare<int>(10, 20);
compare<double>(10.5, 20.5);
// 函数模板实参推演
compare(20, 20); // 还是用的刚才实例化的compare<int>
// compare(30, 40.5); // 错误,推演不出来是什么类型
// 解决方法一:template<typename T, typename E>,a和b用两个类型,各推各的
// 解决方法二:compare<int>(30, 40.5),double强转成int
}
函数模板:不进行编译,因为类型还不知道
模板函数 :在函数调用点,编译器用程序员指定的类型,从原模板实例化一份函数代码出来这就叫做模板函数,这是实例化出来真正需要进行编译的函数 ,因此站在编译器的角度来看,待编译的函数并没有减少,只是我们编写的代码量减少了。同时,实例化出来的模板函数在
.o
文件符号表中产生相应的符号,每个函数名的符号只能出现一次
来看看字符串的情况 (模板的特例化):
cpp
// 针对compare函数模板,提供const char*类型的特例化版本
template<> // 要写上
bool compare(const char* a, const char* b)
{
cout << "compare<const char*>" << endl;
return strcmp(a, b) > 0;
}
// 模板特化不需要在函数名后面加上类型参数
// 即别写成compare<const char*>
int main()
{
// 推演T为const char*,字符串 > 代表的是比较两个常量的地址,要用strcmp才能比较字符串的字典顺序
// 对于某些类型来说,依赖编译器默认实例化的模板代码,代码处理逻辑是错误的
// 这时候,就需要我们进行模板的特例化了,这不是编译器提供的,而是程序员提供的
compare("aaa", "bbb");
compare<const char*>("aaa", "bbb");
// 这两种写法都是对的
}
当然,非模板函数(普通函数)优先被调用
cpp
//非模板函数 - 普通函数
bool compare(const char* a, const char* b)
{
cout << "normal compare" << endl;
return strcmp(a, b) > 0;
}
int main()
{
// 这时候就调用普通函数了,不调用模板函数了
compare("aaa", "bbb");
// 调用模板函数
compare<const char*>("aaa", "bbb");
}
编译器优先把
compare
处理成函数名字,没有的话,才去找compare
模板特例化,如果没有特例化,才进行模板的实例化
分文件编写:
模板代码是不能在一个文件中定义,在另一个文件中使用的,否则链接的时候会出现错误
比如在test.cpp
中存放模板代码,在main.cpp
中声明,这是不可以的,因为声明产生的符号是*UND*
,而在test.cpp
中只有模板,模板本身是不编译的,没有模板实例化出来的compare<int>
等函数,所以不可以
模板代码调用之前,一定要看到模板定义的地方,这样的话,模板才能进行正常的实例化,产生能够被编译器编译的代码。
所以,模板代码都是放在头文件.h
当中的,然后在原文件当中直接进行#include
包含
模板的非类型参数:
必须是整数类型(整数或者地址/引用都可以)是常量,只能使用,而不能修改
模板不仅可以接受类型参数typename T
,还可以接受非类型参数。这些非类型参数可以是整型、指针、引用等。它们在编译时是常量,只能使用,不能修改
示例代码:
cpp
template <int N>
class Array {
public:
int arr[N];
int size() const { return N; }
};
int main() {
Array<5> myArray; // 创建一个包含5个整数的数组
cout << "Array size: " << myArray.size() << endl;
return 0;
}
cpp
// 使用模板实现冒泡排序
template <typename T, int N>
void bubbleSort(T* arr) {
for (int i = N - 1; i >= 1; --i)
{
int flag = 0;
for (int j = 1; j <= i; ++j)
{
if (arr[j - 1] > arr[j])
{
T temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
flag = 1;
}
}
if (flag == 0)
return;
}
}
int main() {
int arr[] = { 64, 34, 25, 12, 22, 11, 90 };
const int size = sizeof(arr) / sizeof(arr[0]);
// 调用冒泡排序模板函数
bubbleSort<int, size>(arr);
cout << "排序后的数组: ";
for (int i : arr)
cout << i << " ";
cout << endl;
return 0;
}