C++中的函数模板

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

template<typename T,typename E>//定义一个模板参数列表,typename也可以用class替换
bool compare(T a,T b){//compare是一个函数模板
	cout<<"template compare"<<endl;
	return a>b;
}
//特例化:
template<>
bool compare<const char*>(const char*a,const char*b){
	cout<<"compare<const char*>"<<endl;
	return strcmp(a,b)>0;//比较ASCII码顺序
}
bool compare(const char*a,const char*b){//#4没有尖括号就是一个普通函数,与模板没有任何关系
	cout<<" normal compare"<<endl;
	return strcmp(a,b)>0;
}


int main(){
	//#1函数调用点
	/*bool compare<int>(int a,int b){
	cout<<"template compare"<<endl;
	return a>b;
	}*/
	compare<int>(1,2);//compare<int>模板名加参数列表合起来才是函数名 
	
	compare(2,3);//#2只用模板名也可以正常调用
	compare(2,3.0);//实参推演不成功报错,解决方法1:指定类型,解决方法2:compare函数模板的形参列表用不同的模板参数(T a,E b)
	
	compare("aaa","bbb");//调用普通函数
	/*如果没有写特例化和普通函数便会实例化出:
	compare<const char*>(const char* a,const char* b){
		cout<<"template compare"<<endl;
		return a>b;#3虽然成功运行,不过比较的是地址顺序,没有意义
	}*/
	compare<const char*>("aaa","bbb");//调用特例化模板函数
	return 0;
}

#1在函数调用点,编译器根据用户指定的类型,从原模板实例化出一份函数代码

实例化出的函数称为模板函数,是真正参与代码编译的函数。函数模板本身无法编译

#2只用模板名也可以正常调用,是模板的实参推演,根据传入的实参类型,来推导出模板类型参数的具体类型。同一种类型,模板只会实例化一次

#3对于某些类型,以来编译器默认实例化的模板代码,代码处理逻辑会有错误,此时需要给模板提供特例化(特殊的实例化),实例化时的模板代码不由编译器提供,而是由用户提供

#4参数列表相同的模板函数、特例化函数、普通函数(构成重载的说法不严谨,因为函数名并不相同,模板函数函数名还包括尖括号),调用优先级:普通函数>特例化>模板函数,不写尖括号优先调用普通函数,再是特例化,再是实参推演,因为编译器优先将compare处理成函数名,找不到对应函数才找函数模板;写了尖括号先调用特例化,再是普通模板函数

函数不会去调用参数列表不同的函数,比如参数是int类型的会去自动调用模板函数并实参推演,而不是调用形参是const char*类型的普通函数

分文件定义声明的情况

模板函数.cpp

#include <iostream>
using namespace std;

template<typename T>
bool compare(T a, T b) {
	cout << "template compare" << endl;
	return a > b;
}
template<>
bool compare<const char*>(const char* a, const char* b) {
	cout << "compare<const char*>" << endl;
	return strcmp(a, b) > 0;
}
bool compare(const char* a, const char* b) {
	cout << " normal compare" << endl;
	return strcmp(a, b) > 0;
}

test.cpp

#include <iostream>

using namespace std;
template<typename T>
bool compare(T a, T b);

int main() {
	//compare(1,2);会报错,因为在其他文件找不到名为compare<int>的函数,因为模板函数不会编译,实例化后才编译
	compare("aaa","bbb" );
	compare<const char*>("aaa", "bbb");
	return 0;
}
//结果是都调用了特例化compare<const char*>
#include <iostream>

using namespace std;
template<typename T>
bool compare(T a, T b);
bool compare(const char* a, const char* b);

int main() {
	compare("aaa","bbb" );//调用普通函数compare
	compare<const char*>("aaa", "bbb");//调用了特例化compare<const char*>
	return 0;
}

总结:模板代码是不能在一个文件中定义,在另外一个文件中使用。模板代码调用之前一定要看到它这个函数名定义的地方,这样模板才能正常实例化,产生能被编译器编译的代码。

所以模板代码一般放在.h文件中,然后在源文件中#include包含

如果一定要分文件,需要在模板函数.cpp中:

#include <iostream>
using namespace std;

template<typename T>
bool compare(T a, T b) {
	cout << "template compare" << endl;
	return a > b;
}

//和特例化有区别,此操作为告诉编译器直接执行指定类型的实例化,不再在调用点实例化
template bool<int>(int,int);
template bool<double>(double,double);
模板的非类型参数

必须是整数类型(int,char,short,long)(整数或地址、引用),都是常量,只能使用,不能修改

#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 + 1] = tmp;
			}
		}
	}
}
int main() {
	int arr[] = { 1,4,235,64,23,7,5 };
	const int size = sizeof(arr) / sizeof(arr[0]);
	//使用方式:
	sort<int, size>(arr);
	for (int val : arr) {
		cout << val << " ";
	}
	cout << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值