1、预备知识
(1)模板参数不仅仅可以是类型参数,还可以是数值型参数。
如:
template
<typename T, int N>//int N就是数值型参数, 要注意这个int类型,因为这里要注意数值型参数的限制,下面有说数值型参数的限制。
void func()
{
T a[N];//使用模板参数来定义局部数组,模板的数值型参数来表示数组的大小。
}
func<double, 10>();//这样进行使用,数值型参数,也就是第二个参数要是常量,因为这是数值型模板参数的限制造成的。
数值型模板参数的限制:变量不能最为模板参数,浮点数不能作为模板参数,类对象不能作为模板参数等。
本质:模板参数是在编译阶段被处理的单元,这点毋庸置疑,因为编译器会首先对模板进行编译,因此,在编译阶段必须准确无误的唯一确定,变量是不能够在编译阶段进行确定的,所以变量
不可以作为模板参数,浮点数因为在计算机的内存中是不精确的,所以C++中不允许浮点数作为模板参数。类对象也不能在编译的时候进行唯一的确定,因为它其实就是一个变量,类的变量摆了。
(2)一道面试题,用你觉得最高效的方法求得1+到N的数值。
template
< int N >//数值型模板参数的函数类模板
class Sum
{
public:
static const int VALUE = Sum<N-1>::VALUE + N;
};
template
< >完全特化
class Sum< 1 >
{
static const int VALUE = 1;
};
int main(void)
{
cout << "1 + 2 + 3 + ... + 100 = " <<Sum<100>::VALUE <<endl;
return 0;
}
解释:上面的程序中,类模板用的是数值型参数,这点从模板参数为int就可以看出来,所以我们使用的时候,直接传递数值就行。VALUE是const的,并且有初始化,所以在编译阶段就会取得
VALUE这个常量的值,将其放入符号表中,同时VALUE又被static修饰,所以是放在全局数据区的。当编译器编译到VALUE时,首先就会去获取这个常量的值进而放入符号表中,但是编译器发现
要想取得VALUE的值,首先要取得N-1的值,要想取得N-1的值,要先取得N-1-1的值,知道N为1的时候,编译器发现有这个类的特化,所以就用了这个特化的类,VALUE的值为1,因为有递归规程,
所以在返回的时候,N不断的又+1,每次+1都会将加完的值放到VALUE这个常量中,直到N变到了N为止,也就是又一直加到了N,最后VALUE的值就完全取得完毕了,最后放入了符号表中。
这是一个高效的求和方法。因为编译器在编译的时候,这个VALUE的常量值就已经确定了,我们后面cout去访问这个值的时候,只是相当于直接从符号表中将值取出来,所以高效。
这个高效的方法依赖了类模板技术、类模板完全特化技术、还依赖了类模板参数为数值型参数的技术,还依赖了对const和static的理解。有了static才可以用作用域分辨符去访问这个VALUE,
有了const才会在编译阶段将值确定,因为常量的值是在编译阶段确定的。