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代码

相关推荐
金色熊族1 小时前
装饰器模式(c++版)
开发语言·c++·设计模式·装饰器模式
Dream it possible!2 小时前
LeetCode 面试经典 150_链表_旋转链表(64_61_C++_中等)
c++·leetcode·链表·面试
CS创新实验室4 小时前
典型算法题解:长度最小的子数组
数据结构·c++·算法·考研408
我有一些感想……4 小时前
浅谈 BSGS(Baby-Step Giant-Step 大步小步)算法
c++·算法·数论·离散对数·bsgs
j_xxx404_4 小时前
C++ STL:string类(3)|operations|string类模拟实现|附源码
开发语言·c++
Elias不吃糖6 小时前
Linux 环境适应 Day 1 全面笔记
linux·c++·笔记
无限进步_7 小时前
C语言字符串连接实现详解:掌握自定义strcat函数
c语言·开发语言·c++·后端·算法·visual studio
oscar9997 小时前
CSP-J教程——第一阶段——第二课:变量与数据类型
c++·数据类型·csp-j
qwepoilkjasd8 小时前
RapidJSON 完整学习指南
c++
一朵筋斗云8 小时前
c++
c++