来看一个小例子:
#include<iostream>
template<long num>
struct Fibonacci
{
static const long val = Fibonacci<num - 1>::val + Fibonacci<num - 2>::val;
};
template<> struct Fibonacci<2> { static const long val = 1; };
template<> struct Fibonacci<1> { static const long val = 1; };
template<> struct Fibonacci<0> { static const long val = 0; };
int main()
{
int i=Fibonacci<10>::val
std::cout<<i;
}
上面程序的输出结果正是斐波那契数列第11个项。与通常的程序不同之处在于,它的结果是在编译时计算出来的。对此我们可以查看反汇编:
可见运行时直接使用的是37h即55这个值。
下面我们来分析一下。
首先定义了一个非类型参数的模板Fibonacci,该模板类定义了一个静态变量val,而val被递归地定义为特化num=num-1和num-2的类中val之和。
所以,val = Fibonacci<num - 1>::val + Fibonacci<num - 2>::val
而Fibonacci<num - 1>::val
又被递归定义为val = Fibonacci<num - 2>::val + Fibonacci<num - 3>::val
,同理Fibonacci<num - 2>::val
被递归定义为Fibonacci<num - 3>::val+Fibonacci<num - 4>::val
。
既然是递归,就必须有边界条件作为递归的终点。
所以我们特化当num=0,1,2时val的值为确定的0,1,1。
template<> struct Fibonacci<2> { static const long val = 1; };
template<> struct Fibonacci<1> { static const long val = 1; };
template<> struct Fibonacci<0> { static const long val = 0; };
因为模板是在编译时被推导展开的,所以Fibonacci数列的值也就在编译时被计算出来了。
再举一个阶乘的小例子:
#include<iostream>
template<long num>
struct Factorial
{
static const long val = num*Factorial<num - 1>::val;
};
template<> struct Factorial<1> { static const long val = 1; };
int main()
{
int fib = Factorial<10>::val;
std::cout << fib;
}
思路完全相同,这里就不再赘述。
ps:template元编程是图灵完备的,也就是说,任何程序中需要表达的计算,都可以采用这种方式表达。