函数模板
在C++当中会有一些情况,比如说静态多态的情况,我们需要相加两个参数,代码如下:
int Add (int a, int b) {
return a + b;
}
int Add (double a, double b) {
return a + b;
}
如果对每个希望去相加的类型都要写一个函数,是一种非常繁琐的事情,这时就体现出了模板函数的用途了。
我们可以把模板函数看作是一个公式,可以用来生成针对特定类型的函数版本。那么Add函数就可以写成如下形式:
template <typename T>
int Add(const T &a, const T &b) {
return a + b;
}
当用到模板时,T就是一个类型,T表示的实际类型在编译时根据实参来决定的,这时我们可以用任何类型进行Add函数了。编译器推断出参数类型后就会为我们实例化一个特定版本的函数。
我们再升级一下这个函数,如下:
#include <iostream>
using namespace std;
template <class T>
T Add(const T& a, const T& b) {
return a + b;
}
int main() {
double a = 3.14159;
int b = 2;
int c = 3;
double d = 1.23456;
cout << Add(b, c) << endl;
cout << Add(a, d) << endl;
return 0;
}
上面的程序有一点不同是把template<typename T>
换成了template <class T>
,虽然用typename指定模板类型参数比class更为直观,但是它们两个并没有什么区别,typename是在模板广泛应用以后才引入到C++里的(C++ primer P580),有些程序员还是用class的。
这样就不用写不同类型的返回值的函数。
非类型模板参数
当一个模板被实例化时,非类型参数会被常量表达式所代替,然后编译器实例化模板。
下面有举一个例子:
#include <iostream>
using namespace std;
const int num1 = 3;
const int num2 = num1 + 1;
template <unsigned N, unsigned M>
char * Add(char a[N], char b[M]) {
char* sum = strcat(a, b);
return sum;
}
int main() {
char a[num1] = "hi";
char b[num2] = "sam";
char* add = Add<num1, num2>(a, b);
cout << add << endl;
return 0;
}
这里的N, M是num1和num2。而num1和num2就是常量表达式。非类型参数还可以是指向对象或者函数类型的指针或引用。绑定的指针或者引用必须要有静态的生存期,就是不能用非static局部变量或者动态对象作为指针或引用来初始化模板参数。
在模板定义内,模板非类型参数是一个常量值。需要常量表达式的地方就可以使用非类型参数,例如数组大小。