模版编程 在编译期完成递归工作
斐波那契数
斐波那契数形如:0,1,1,2,3,5,8,13.....。该序列的通用方程式:Fib(n)=Fib(n-1)+Fib(n-2),递归生成斐波那契数的典型函数如下:
unsigned RecursiveFib( unsigned n)
{
if(n<=1)
return n;
return RecursiveFib(n-1)+RecursiveFib(n-2);
}
这个程序的时间复杂度是指数级的,它非常低下,根本不能应用于产品中。
但是距离模板化版本只有一步之遥。
template< unsigned N> struct Fib
{
enum
{
//递归定义
Val=Fib< N-1 >::Val+Fib <N-2>:Val
};
};
//模板特化,结束条件
template <> struct Fib <0> { enum { Val=0}; };
template <> struct Fib <1> { enum { Val=1}; };
//让该模板形如函数
#define FibT( N ) Fib< n >::Val
通过#define“调用”此模板:
std::cout<< FibT( 4 ); //Fib< 4 >::Val
std::cout<< FibT( 4 ); //Fib< 4 >::Val
此模板化版本有几个注意点:
1.此模板数不是真正的函数-----它是叫做Val的枚举类型,在编译期递归生成,
Val=Fib< N-1 >::Val+Fib< N-2 >::Val并不常见,但是合法。
2.模板参数N用于指定函数的输入,并不常见,但完全可行。
3.要终止递归,需要正确处理结束条件,对斐波那契数来说,结束条件是N为0和1时,
本模板中使用的是模板特化。
4.如果当i还是可变的变量时调用FibT(i),将会产生编译错误。
1.此模板数不是真正的函数-----它是叫做Val的枚举类型,在编译期递归生成,
Val=Fib< N-1 >::Val+Fib< N-2 >::Val并不常见,但是合法。
2.模板参数N用于指定函数的输入,并不常见,但完全可行。
3.要终止递归,需要正确处理结束条件,对斐波那契数来说,结束条件是N为0和1时,
本模板中使用的是模板特化。
4.如果当i还是可变的变量时调用FibT(i),将会产生编译错误。
=Fib< 4 >::Val
=Fib< 3 >::Val + Fib< 2 >::Val
=Fib< 2 >::Val +Fib< 1>::Val + Fib< 1 >::Val + Fib< 0 >::Val
=Fib< 1>::Val + Fib< 0 >::Val + 1+1+0
=1+0+1+1+0
=3
由于所有的输入在编译器都确定了,所以编译程序可以将Fib< N >换算成常数。
std::cout<< FibT( 4 );//与3完全等价
该方法可以成为你C++工具包中的有用工具,你很可能会有指数级运行时间不能降为零的情况,通过使用模板元编程,就可以通过增加额外的编译时间来减少执行时间。
=Fib< 3 >::Val + Fib< 2 >::Val
=Fib< 2 >::Val +Fib< 1>::Val + Fib< 1 >::Val + Fib< 0 >::Val
=Fib< 1>::Val + Fib< 0 >::Val + 1+1+0
=1+0+1+1+0
=3
由于所有的输入在编译器都确定了,所以编译程序可以将Fib< N >换算成常数。
std::cout<< FibT( 4 );//与3完全等价
该方法可以成为你C++工具包中的有用工具,你很可能会有指数级运行时间不能降为零的情况,通过使用模板元编程,就可以通过增加额外的编译时间来减少执行时间。