模板编程
基本语法
template <typename/class T>
template是告诉编译器,接下来是一个模板,其中 typename和class是关键字,在这里二者没有什么区别或者说可以替换使用。其中T叫做模板形参,一旦被实例化,那么T就会变成具体的类型。
模板函数
template <typename T>
T add(const T lva, const T rva)
{
T a ;
a = lva + rva;
return a;
}
所有的模板函数都是template语句为开始,从而告诉编译器这是一个模板和参数类型这些必要信息,T的话可以取任意的名字,模板参数的个数也是任意可以替换的。注意: 例如template <typename T1, typename T2 = int> 函数模板是支持默认参数的,T1、T2的顺序在默认情况下是可以任意的,不用严格按照从左到右的顺序。
如果我们写出add(1,2)和add(2.4,3.6)这样的函数,那么在向add提供参数的时候,编译器就会自动分析参数的类型,然后将所用到的T定义换成相对应的类型,以上两个函数在编译期间将会生成
int add(const int lva, const int rva)
{
int a ;
a = lva + rva;
return a;
}
或者是
double add(const double lva, const double rva)
{
double a ;
a = lva + rva;
return a;
}
但是当我们调用函数add(1.0, 1)就会报错,编译器无法找到add(int, double), 因为typename定义为T,T只能被定义为同一个类型,不可能定义为两个不同的类型。你可能会说匹配add(double, double),这个就涉及到函数重载的问题了。到底是匹配add(double, double)还是匹配add(int, int)呢?编译器也不知道,那就报错吧。
类模板和成员模板
C++支持对类的模板化,如下所示,就是一个类的模板
template <class T>
class Myclass
{
T a;
public:
T add(const T lva, const T lva);
};
template <class T>
T Mycalss<T> :: add(const T lva, const T rva)
{
a = lva + rva;
return a;
}
类模板和函数模板的区别在于,函数模板会根据参数推断类型,当然类模板也支持默认参数,但是类模板必须严格从右往左默认化。
成员模板
成员模板就是在模板中嵌套一层模板,如下所示的代码:
template <class T>
class Myclass
{
T a;
public:
template <typename type_1, typename type_2>
type_1 add(const type_1 lva, const type_2 lva);
};
template <class T>
template <typename type_1, typename type_2>
type_1 Mycalss<T> :: add(const type_1 lva, const type_2 rva)
{
a = lva + rva;
return a;
}
在上面这个勒种使用了一个嵌套的模板声明,且通过作用域符号::指出add是类的成员,需要注意的是,有些编译器不支持模板成员,而有些编译器不支持类外的定义。
模板类中的静态成员
因为在类中定义的静态成员是存储在静态区中,被所有的类对象所共享,在模板中静态成员也不会被复制多份,而是被同类实例化的类对象所共享。
typename 和 class
class先出现,typename后出现,两者在使用时很少有区别的。