函数模板

函数模板的概念

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

函数模板的格式

template <typename T1, typename T2, .......  typename Tn>

返回值类型 函数名(参数列表){} typename 也可以用class代替,两者是一样的。

template <class T>
void Add(T& lest, T& right)
{
  return left + right;
}

函数模板的原理

一句话,就是帮助我们解决重复性工作的模具。模板是一个蓝图,它本身不是函数,是编辑一起用使用方式产生特定具体类型函数的模具,所以模板就是讲本来应该我们做的重复的事情交给了编译器。

int Add(int left, int right)
{
  return left + right;
}

double Add(double left, double right)
{
  return left + right;
}

char Add(char left, char right)
{
  return left + right;
}

int main()
{
  Add(1, 2);
  Add(1.2, 2.3);
  Add('1', '2');
  return 0;
}

加法函数,不同的数据类型,就需要调用不同的方法,来完成同一个功能,函数的重复率太高,而且维护起来比较麻烦,这个时候我们就可以用模板来实现这个加法函数。

template <class T>
T Add(T lest, T right)
{
  return left + right;
}

int main()
{
  Add(1, 2);     // int
  Add(1.2, 2.3);  // double
  Add('1', '2');  // char
  return 0;
}

函数模板的实例化

函数模板的实例化,也就是将函数模板参数具体化。

隐式实例化

template <class T>
T Add(T lest, T right)
{
  return left + right;
}

int main()
{
  // 对函数模板进行实例化
  Add(1, 2);     // int
  Add(1.2, 2.3);  // double
  Add('1', '2');  // char
  return 0;
}

编译器在编译阶段,用户对哈数模板实例化之后,编译器会对实参类型进行推演,根据推演的结果来确定模板参数列表中T的实际类型,根据确定的T具体类型来生成处理具体类型的函数。类型转换只是在编译器编译时进行,编译器在生成代码时不会进行隐式类型转化。

Add(1, 2.3);

在隐式实例化中,该语句不能编译通过,在编译期间,编译器对模板类型进行推演室,无法确定T的具体类型,只能报错。在模板中,编译器一般不会进行类型转换。
解决上面的方法有两种:

  1. 用户自己强转
Add(1, (int)2.3);
  1. 采用显式实例化

显式实例化

在函数名后面的<>中指定函数模板的实际类型

Add<int>(1,2.3);  T--->int
Add<double>(1,2.3);  T--->double

编译器在编译代码期间,看到对函数模板进行显式实例化之后,直接根据显式实例化的T的具体类型直接生成代码。如果不匹配,编译器还可能进行隐式实例化,否则就会报错。

函数模板参数的匹配原则

  1. 一个非模板函数可以和一个同名的函数模板同时存在,该函数模板还可以被实例化为这个非模板函数
// 专门处理int的加法函数
int Add(int left, int right)
{
  return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
  return left + right;
}
void Test()
{
  Add(1, 2); // 与非模板函数匹配,编译器不需要特化
  Add<int>(1, 2); // 调用编译器特化的Add版本
}

如果有对应的非模板函数,编译器会优先调用,不需要再将函数模板进行实例化后调用。模板函数不允许自动转换类型,但普通函数可以自动转换类型

  1. 函数模板可以被实例化成不同类型的参数
template<class T1, class T2>
T1 Add(const T1& left, const T2& right)
{
	return left + right;
}


int main()
{
	Add(1, 2);  T1---->int 
	Add(1, 2.0);   T1---->int, T2---->double
	return 0;
}

类模板

类模板的定义格式

template<class T1, class T2, ....., class Tn>
class 类模板名
{
   // 类内成员定义
};

类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后加<>,然后将实例化的类型放在<>之中,类模板名字不是真正的类,而实例化的结果才是真正的类。

Vector<int> s1;//Vector 类模板名(不是真正的),Vector<int >才是类型
Vector<double> s2;

更多推荐

函数模板主要内容