C++ 函数模板

  • 函数模板是通用的函数描述,是使用泛型来定义的函数。
  • 泛型可用具体的类型(如int,double)来替换。


1. 函数模板

1.1 什么是函数模板

  • 函数模板允许使用任意的类型来定义函数,例如,可这样建立一个swap模板:
template <typename T>		// 该句可改为: template <class T>
void swap(T& a, T& b){
	T temp;
	temp = a;
	a = b;
	b = temp;
}
  • 上述代码第一行中 templatetypename是必须的,可以使用 class 代替typename(C++98新增关键字typename)。
  • 此外,必须使用尖括号<>
  • 函数模板的声明声明和定义都需要加 template <typename T>

    测试代码如下:

#include <iostream>

template <typename T>
void Swap(T& a, T& b);      // 1. 模板函数-原型   

int main() {                // 3. 主函数测试
    using namespace std;
    int a =  10;
    int b = 999;
    
    Swap(a,b);
    cout << "a:" << a << ", b:" << b << ".\n";
    
    return 0;
}

template <typename T>		// 2. 模板函数-定义   
void Swap(T& a, T& b){
	T temp;
	temp = a;
	a = b;
	b = temp;
}

a:999, b:10.

1.2 重载的函数模板

  • 需要对 多个对不同类型 使用同一种算法的函数时,可以像重载常规函数定义那样 重载模板定义。和常规的重载一样,被重载的模板的函数特征必须不同。
  • 与 1.1测试代码 不同,本小结测试代码新增一个模板,其特征为(T[],T[], int)
#include <iostream>

    
template <typename T>
void Swap(T& a, T& b);          // 模板函数 1 

template <typename T>
void Swap(T* a, T* b, int n);   // 模板函数 2 

int main() {                   
    using namespace std;
    
    int a =  10;				// 测试 模板函数 1
    int b = 999;
    Swap(a,b);
    cout << "a:" << a << ", b:" << b << ".\n";
    
    int arr[5] = {1,2,3,4,5};	// 测试 模板函数 2
    int brr[5] = {11,12,13,14,15};
    Swap(arr,brr,5);
    cout << "arr: ";
    for (auto i:arr)
        cout << i << " ";
    
    return 0;
}

template <typename T>		// 模板函数 1
void Swap(T& a, T& b){
	T temp;
	temp = a;
	a = b;
	b = temp;
}

template <typename T>		// 模板函数 2
void Swap(T* a, T* b, int n){
	T temp;
	for (int i=0; i<n; ++i){
	    temp = a[i];
    	a[i] = b[i];
    	b[i] = temp;
	}
}

a:999, b:10.
arr: 11 12 13 14 15


2. 具体化

2.1 显式具体化

  • 当类型为某些无法处理的特殊类型时,我们需要对 这些特殊类型 提供具体化的模板定义。假设有如下结构:
struct job{
	char name[40];
	double salary;
};
  • 上述的结构使用第一节中的模板函数也可以完成交换,C++中允许一个结构赋值给另一个。
  • 但是,当我们只想交换 salary成员值时,就需要提供一种具体化函数–称为显式具体化

要点总结:

  • I. 对于给定的函数名,可以有非模板函数模板函数显式具体化模板函数 以及他们的重载。
  • II. 显式具体化的原型和定义应以 template<> 打头,并通过名称来指出类型。
  • III 编译器在选择原型时的优先级: 非模板 > 具体化 > 模板
void Swap(job& a, job& b);					// 1. 非模板函数原型

template<typename T>
void Swap(T& a, T& b);						// 2. 模板函数原型

template<> void Swap<job>(job& a, job& b);	// 3. 显式具体化
  • Swap<job> 中的 <job> 是可选的,因为函数的参数类型表明,这是job的一个具体化。
  • 因此,上述代码中 显式具体化 原型也可以这么写:
template<> void Swap(job& a, job& b);		// 3. 显式具体化

    测试代码:

#include <iostream>

struct job{
	char name[40];
	double salary;
};
    
template <typename T>
void Swap(T& a, T& b);                      // 常规版本

template <> void Swap<job>(job& a, job& b); // 显式具体化

using namespace std;
int main() {    
    
    job job_a = {"mike",100.0};         	// 测试 显式具体化
    job job_b = {"alex",888.8}; 
    Swap(job_a,job_b);
    
    cout << "job_a: " << job_a.name << ", salary:" << job_a.salary << endl;
    cout << "job_b: " << job_b.name << ", salary:" << job_b.salary << endl;
    
    return 0;
}

template <typename T>
void Swap(T& a, T& b){
	T temp;
	temp = a;
	a = b;
	b = temp;
}

template <>	void Swap<job>(job& a, job& b){ 
	double temp;
	temp = a.salary;
	a.salary = b.salary;
	b.salary = temp;
}

job_a: mike, salary:888.8
job_b: alex, salary:100

2.2 实列化

  • 当编译器使用模板为特定的类型生成函数定义时,得到的是模板实列化
  • I. 隐式实列化:i、jint类型,调用Swap(i,j); 将导致编译器生成Swap()的一个实列,该实列使用int类型, 注意:模板并非函数定义,但使用int的模板实列是函数定义,这种实列化叫 隐式实列化
  • II. 显式实列化: 直接命令编译器创建特定的实列,如Swap<double>(),这种实列化成为显式实列化
                I. 其声明使用<>来指示类型.
                II. 在声明前加关键字 template
template void Swap<double>(double, double);	// 显式实列化

2.3 实列化 与 具体化

  • 我们可以看到,显式实列化显式具体化十分相似。
template void Swap<double>(double, double);			// 显式实列化

template<> void Swap<double>(double& , double& );	// 显式具体化-1
template<> void Swap(double& , double& );			// 显式具体化-2
  • 显式实列化显式具体化二者区别:
  • I. 显式具体化意思是不要使用Swap()模板来生成函数定义,应该使用专门为 double 类型显式定义的函数定义。这些原型必须有自己的函数定义。
  • II. 显式具体化声明在关键字 template 后有<>, 而显式实例化没有。
  • III. 试图在同一个文件中使用同一种类型的 显式实列化 和显式具体化将出错。
  • 隐式实列化、显式实列化、显式具体化 统称为 具体化。他们的相同之处在于,它们表示的都是使用具体类型的函数定义,而不是通用描述。
  • 本小节不写例子了,会看起来很乱,下面的代码对 具体化 进行了总结:
...
template <typename T>
void Swap(T&, T&);                          // 1. 模板原型

template<> void Swap<job>(job&, job&);      // 2. 显式具体化

int main(){
    template void Swap<char>(char&, char&); // 3. 显式实列化
    
    short a,b;
    ...
    Swap(a,b);                              // 4. 隐式实列化
    
    job n,m;
    ...
    Swap(n,m);  // 使用显式具体化
    
    char g,h;
    ...
    Swap(g,h);  // 使用显式实列化
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值