C++ Primer 第十六章 16.1定义模板

本文详细介绍了C++中的函数模板定义,包括如何使用template关键字及模板参数列表来定义模板,以及实例化的过程。内容涵盖模板参数类型推断、typename/class声明、非类型模板参数和inline/constexpr修饰模板函数。此外,讨论了函数模板错误通常在实例化阶段报告,并通过练习解释了实例化概念和模板函数的使用限制。标准库中的begin和end函数可能也使用了模板,以实现对不同容器的通用性。最后,建议在迭代器遍历时使用!=而非<,以确保代码的通用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

16.1.1 定义函数模板

使用template+模板参数列表来定义一个函数模板。

template<typename T>
bool compare(const T&a,const T&b){
	return a<b;
}

compare(1,1);

在具体调用时,会根据传入的实参类型,将函数模板中的模板参数替换掉,转换为一个具体的函数实例。 这个过程叫做实例化。函数模板可以根据传入的实参类型推断出模板参数类型,前提是所有的模板参数类型都用到,我们也可以自己指定参数类型。

compare<int,int>(1,1);

我们可以使用typename和class声明模板参数,但是一般使用typename,因为这样更加的清晰,class是旧版本遗留下来的。

使用typename和class声明的参数模板是一个类型,但是这个类型具体是什么要在根据传入的实参类型来确定。我们还可以当以非类型模板参数非类型模板参数它本身就已经是一个具体的类型的变量了,这个值由用户提供或者编译器推断

下面的调用方式就是由编译器自己推断得出的,用来获取数组的大小。

template<typename value_type, unsigned arr_size>
constexpr unsigned get_arr_size(value_type(&arr)[arr_size]) {
	return arr_size;
}
int a[] = {1,2,3,4,54,56};
	int b[get_arr_size(a)];

下面这种就是用户自己指定的

template<typename T,unsigned  vlaue>
void print(T v) {
	cout<<v<<endl;
}

print<int, 1>(233);

模板函数一样的可以被inline和constexpr修饰。

模板的声明和定义都放在一块且放在头文件中,而不是像普通的类一样,声明和定义分别在头文件和源文件中

函数模板的很多错误都是在实例化的阶段报告。
在这里插入图片描述

练习
16.1

实例化就是为模板创建一个具体的例子,在函数模板中体现是函数模板根据传入的实参类型将模板参数变为实参的类型生成一个具体的函数。

16.2

如果传入一个int和一个double类型的变量则会报错,因为函数模板无法实例化出一个形参列表为int,double的compare

template <typename T>
bool compare(const T& a, const T&b) {
	return a < b;
}

cout<<compare(1, 2)<<endl;
cout<<compare(2.2, 2.2)<<endl;
16.3

编译报错,提示Sales_date没有重载<运算符

cout<< compare(data1, data2)<<endl;
16.4
template <typename Iter_type,typename Value_Type>
Iter_type my_find(const Iter_type& begin,const Iter_type& end,Value_Type target_value) {
	Iter_type target_iter = end;
	for (Iter_type iter = begin;iter!=end;++iter)
	{
		if (*iter==target_value)
		{
			target_iter = iter;
			break;
		}
	}
	return target_iter;
}
16.5
template<typename value_type,unsigned arr_size>
void print(value_type (&arr)[arr_size]) {
	for (auto item :arr)
	{
		cout << item << endl;
	}
}

	int a[] = {1,2,3,4,54,56};
	double b[] = {2,3,4,54,654};
	string c[] = {"12312","2222","6666"};
	print(a);
	print(b);
	print(c);
16.6

标准库对数组的begin和end,很可能也是使用模板函数,对于begin则返回首元素地址,对于end则返回首元素地址+元素个数

template<typename value_type, unsigned arr_size>
value_type* my_end(value_type(&arr)[arr_size]) {
	return arr + arr_size;
}

template<typename value_type, unsigned arr_size>
value_type* my_begin(value_type (&arr)[arr_size]) {
	return arr;
}

int a[] = {1,2,3,4,54,56};
	for (auto iter = my_begin(a); iter !=my_end(a);++iter)
	{
		cout << *iter << endl;
	}
16.7
template<typename value_type, unsigned arr_size>
constexpr unsigned get_arr_size(value_type(&arr)[arr_size]) {
	return arr_size;
}

//因为创建数组需要输入常量表达式,为了验证
//返回的是常量表达式所以使用get_arr_size()的实例
//创建一个数组
int a[] = {1,2,3,4,54,56};
	int b[get_arr_size(a)];
	auto value = get_arr_size(a);
	cout << value << endl;
16.8

在这里插入图片描述
截图来自C++ Primer第97页,一个直接的原因是对迭代器使用!=在所有的标准库容器上都是可以使用的,但是<符号则不一定适用,有些容器没有定义<,比如关联式容器,list等等,因此为了更加的让代码更加通用在迭代器和指针的遍历中使用!=更好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值