一般的函数可以take arguments of specific types and have a specific return type。
模板函数(template function)处理的是generic type(泛类型)。 这样, 我们就可以用同一个模板函数去套多个不同的类型的函数。
例如:
下面两个函数是不同的, 但是做的事情却相同, 均是求和:
int sum(const int x, const int y) {
return x + y;
}
和
double sum(const double x, const double y) {
return x + y;
}
上述用到的方法是重载。 重载的坏处是必须编写两个独立的代码, 尽管从高层看, 二者做的是相同的事情。 为了避免这个问题, 我们常常使用它模板。模板的好处是支持泛型编程。 泛型编程是一种再算法中使用泛型参数的方法, 以适应各种不同的数据类型和数据结构。
为了进一步的抽象, generalize, 编写如下的模板函数:
template <class Type>
Type sum(const Type x, const Type y) {
return x + y;
}
下面举一个例子:
#include <iostream>
using namespace std;
template <class Type>
Type sum(const Type a, const Type b) {
return a + b;
}
int main() {
cout << sum<int>(1, 2) << endl;
cout << sum<float>(1.21, 2.43) << endl;
return 0;
}
运行结果:
注意, 我们其实不需要像上面那样明确的给出参数的类型, 下面的调用方式也是有效的。
int main() {
cout << sum(1, 2) << endl;
cout << sum(1.21, 2.43) << endl;
return 0;
}
Templates can also specify more than one type parameter:
如下:
#include <iostream>
using namespace std;
template <class T, class U>
U sum(const T a, const U b) {
return a + b;
}
int main() {
cout << sum<int, float>(1, 1.4) << endl;
//below is also okay
cout << sum(1.3, 6) << endl;
cout << sum(1.3, 6.0);
return 0;
}
运行结果如下:
模板函数也可以重载。
一个模板函数可以被模板函数或者一般同名函数重载。 这时候, 重载函数的匹配过程如下:
(1)调用一个完全匹配的普通函数
(2)调用一个模板函数, 它可以创建为一个完全匹配的函数
(3)试着对普通函数重载解析, 然后调用完全匹配的那个函数。
#include <iostream>
#include <string>
using namespace std;
template <class Type>
void display(Type x) {
cout << "Template display: " << x << "\n";
}
void display(int x) {
cout << "Explicit display: " << x << "\n";
}
int main() {
display(100);
display(12.0);
display('c');
return 0;
}
注意上例的display(100)会调用display()函数的普通版本, 而非模板函数。
运行结果如下:
模板类
#include <iostream>
using namespace std;
template <class Type>
class Point {
private:
Type x, y;
public:
Point(const Type u, const Type v ): x(u), y(v) {}
Type getX() {
return x;
}
Type getY() {
return y;
}
};
int main() {
Point<float> fpoint(2.5, 3.5);
cout << fpoint.getX() << "," << fpoint.getY() << endl;
return 0;
}
运行结果:
to declare member functions externally, we use the following syntax:
template <class T>
T classname<T>:: function_name()
例如, 对于上例, 类外如下定义函数getX:
template <class Type>
Type Point<Type>::getX() {
return x;
}
模板类也可以带多个表示类型的参数(泛型数据类型)。 如下:
template <class T1, class T2, ... >
class classname {
......
};
模板类可以向模板函数一样重载。
#include <iostream>
#include <cctype>
using namespace std;
template <typename T>
class Container {
private:
T elt;
public:
Container(const T arg) : elt(arg) {}
T inc() { return elt+1; }
};
template <>
class Container <char> {
private:
char elt;
public:
Container(const char arg) : elt(arg) {}
char uppercase() { return toupper(elt); }
};
int main() {
Container<int> icont(5);
Container<char> ccont('r');
cout << icont.inc() << endl;
cout << ccont.uppercase() << endl;
return 0;
}
运行结果:
NOTE: 上述类Container 有两种implementations, 分别为:
(1)a generic one(泛型类)
(2)a one specifically tailored ro char type.
最后, 我们可以用一般的类型去参数化类, 如下例:
#include <iostream>
using namespace std;
template <typename T, int N>
class ArrayContainer {
private:
T elts[N];
public:
void set(const int i, const T val) { elts[i] = val; }
T get(const int i) { return elts[i]; }
};
int main() {
ArrayContainer <int, 5> intac; // 5 element array of ints
ArrayContainer <float, 10> floatac; // 10 elements array of float
intac.set(2, 3);
floatac.set(3, 3.5);
cout << intac.get(2) << endl;
cout << floatac.get(3) << endl;
return 0;
}
运行结果如下:
注意我们也可以对模板的参数设定为具有default value的, 例如:
template <typename T=int, int N=5>
class ArrayContainer {
..
};
当我们使用默认参数的时候, 直接使用如下声明创建:
ArrayContainer<> identifier;