C++模板编程—学习C++类库的编程基础


课程总目录


文章目录


一、详解函数模板

模板的意义:对类型也可以进行参数化了

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;
}

二、初识类模板

三、理解容器空间配置器allocator的重要性

四、实现C++STL向量容器vector代码

相关推荐
敲上瘾6 分钟前
操作系统的理解
linux·运维·服务器·c++·大模型·操作系统·aigc
不会写代码的ys12 分钟前
【类与对象】--对象之舞,类之华章,共绘C++之美
c++
兵哥工控14 分钟前
MFC工控项目实例三十二模拟量校正值添加修改删除
c++·mfc
长弓聊编程24 分钟前
Linux系统使用valgrind分析C++程序内存资源使用情况
linux·c++
cherub.31 分钟前
深入解析信号量:定义与环形队列生产消费模型剖析
linux·c++
暮色_年华1 小时前
Modern Effective C++item 9:优先考虑别名声明而非typedef
c++
重生之我是数学王子1 小时前
QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
开发语言·c++·qt
我们的五年1 小时前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
做人不要太理性2 小时前
【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!
c++·哈希算法·散列表·unordered_map·unordered_set
程序员-King.2 小时前
2、桥接模式
c++·桥接模式