泛型编程 实例 阶乘
来源:互联网 发布:淘宝服装设计 编辑:程序博客网 时间:2024/05/29 09:04
1-递归求阶乘
模板元编程:编译期得到结果
步骤:
1-递归模板具现化实现循环
template<unsigned n>
struct factorial{
enum{value =n*factorial<n-1>::value};
};
2-模板特化结束循环
template<>
struct factorial<0>{
enum {value=1};
};
调用factorial<n>::value
调用factorial<10>::value
2- 求3的N次方
原理
模板元编程的工作:递归的模板实例化
计算3^N的递归模板实例化应用以下2个规则:
1.3^N=3*3^(N-1)
2.3^0=1
枚举值实现
Step1:第1个模板实现一般的递归原则
template<int N>
class pow1{
public:
enum{result=3*pow3<N-1>::result};
};
Step2:第2个模板结束递归的特化,确定pow3<0>的结果
template< >
class pow1<0>{
public:
enum{result=1};
};
效果:调用pow3<7>::result
编译器实例化pow3<7>,获得3*pow3<6>::result
实例化pow3<6>,获得3*pow3<5>::result
类似的,递归不断进行,直到pow3<>基于0进行实例化,递归结束,
1作为pow3<7>的结果
静态常量实现
step1-计算3的N次幂的基本模板
templ<int N>
class pow3{
public :
static int constresult=3*pow3<N-1>::result;
};
step2-用于结束递归的局部特化
template<>
class pow3<0>{
public:
static int const result=1;
};
缺点:静态成员变量只能是左值,
因此,如果声明如下:
void foo(int const &);
把模板元程序的结果传递时,即:
foo(pow3<7>::result);
编译器必须传递pow3<7>::result的地址,----》这会强制编译器实例化静态成员的定义,并为定义分配内存
但枚举值却不是左值(它们没有地址)。
所以:通过引用传递枚举值时,不使用任何静态内存,[<template C++>中使用枚举值]计算平方根
原理
递归过程是由二分查找。
使用?:判断位于LO,Hi的前半部分还是后半部分
如果mid^2大于N,在前半部分进行查找;否则在后半部分查找
递归结束条件:LO,HI具有相同的值M,其中M就是最终结果
步骤
step1-sqrt(N)的基本模板
template<int N, int LO=1,int HI=N>
class mysqrt{
public:
enum{mid=(LO+HI+1)/2};//计算中点
//二分查找一个较小的result
enum{result=(N<mid*mid)?:mysqrt<N,1,mid-1>::result
:mysqrt<N,mid+1,N>::result};
};
step2-局部特化,适用于LO==HI
template<int N,int M>
class mysqrt<N,M,M>{
public:
enum{result=M};
};
实例化—扩展过程
mysqrt<16>::result
扩展为: mysqrt<16,1,16>::result
直到mysqrt<16,4,4>::result结束了整个递归
缺点:完全实例化
当编译器计算下面表达式的时候:
(16<8*8)?:mysqrt<16,1,8>::result
: mysqrt<16,9,16>::result
编译器实例化了mysqrt<16,1,8>,
也实例化了mysqrt<16,9,16>,完全实例化mysqrt<16,9,16>将会促使mysqrt<16,9,12>,mysqrt<16,13,16>的完全实例化
最终实例化题总数大约是N的2倍
更好的实现 ifelse
1-基本模板
template<bool C,typename TA,typename TB>
class ifthenelse;
2-局部特化,true意味着选择第2个实参
template< typename TA,typename TB>
class ifthenelse<true,TA,TB>
{
public:
typedef TA result;
};
3-局部特化,false意味着选择第3个实参
template< typename TA,typename TB>
class ifthenelse<false,TA,TB>
{
public:
typedef TB result;
};
step1-sqrt(N)的基本模板
template<int N, int LO=0,int HI=N>
class mysqrt{
public:
enum{mid=(LO+HI+1)/2};//计算中点
使用二分法查找一个较小的值
typedef typename ifthenelse<N<mid*mid>,mysqrt<N,LO,HI>,mysqrt<N,mid,HI>>::result
subt;
enum{result=subt::result};
};
step2-局部特化,适用于LO==HI
template<int N,int M>
class mysqrt<N,M,M>{
public:
enum{result=M};
};
或者等价于下面实现
template<int N,int S>
class mysqrt<N,S,S>
{
public:
enum{result=S};
};
现在:不会完全实例化了,实例化体数量趋向于log2(N)
自然且迭代的算法
原理
为了计算N的平方根,使用迭代,I的值从0迭代到N,直到I^2 >=N
此时,I即是N的平方根(不考虑不存在平方根的情况)
C++实现
int I;
for(I-0;I*I<N;++I)
{
;
}
//I是N的平方根
实现:
step1-迭代计算平方根的基本模板
template<intN,int I=0>
class sqrt{
public:
enum{result=I*I<N?:sqrt<N,I+1>::result
:I;}
};
用于结束迭代的局部特化
template<intN>
classsqrt<N,N>{
public:
enum{result=N};
};
若I*I<N,下次迭代sqrt<N,I+1>::result作为本次的result;
否则将I作为本次的result
计算sqrt<4>的实例化过程
result=(1*1<4)?sqrt<4,2>::result:1
result=(1*1<4)?(2*2<4)?sqrt<4,3>::result:2:1
以此类推,直到找到结束递归的特化才结束,
也就是说,如果没有提供特化,编译器将继续进行实例化,直到达到编译器内部实例化个数的最大值。
IFTHENELSE模板解决:
step1-模板参数作为result的基本模板
template<int N >
class value{
public:
enum{result=N};
};
step2-迭代计算平方根
template<intN,int I=0>
class sqrt{
public:
typedef typenameifthenelse<(I*I<N),sqrt<N,I+1>,value<I>
>::result
subt;
enum{result=subt::result};
};
优点:
使用ifthenelse模板后,实例化的数量接近于sqrt(N),不是原来的N了
通过上面例子,可总结出模板元编程的几个部分:
模板参数
迭代构造:通过递归
路径选择:使用条件表达式或特化
整型(即枚举里的值应该为整型)
如果对递归实例化体和模板参数的数量没有限制,对于编译期可计算的任何对象,都可以使用元编程;
但C++标准建议最多进行17层的递归实例化,然而大多数编译器都能够处理至少几十层,有些编译器答应实例化至数百层,更有一些可达数千层,直至资源耗尽。
实际开发中,很少使用模板 元编程(有些情况下高效)- 泛型编程 实例 阶乘
- 【转】Java编程实例:计算阶乘的四个例子
- Java编程实例:计算阶乘的四个例子
- Java编程实例:计算阶乘的四个例子
- C#基础编程---阶乘
- 编程练习:阶乘
- Java编程之阶乘
- Java 递归实例 – 阶乘
- C# 2.0泛型编程基础实例
- 编程之美之阶乘
- [编程之美]阶乘问题
- C#编程实现阶乘算法
- 递归实例 求5的阶乘
- C语言——实例026 阶乘
- AngularJS(五)阶乘实例1
- AngularJS(五)阶乘实例2
- AngularJS(五)阶乘实例3
- 关于阶乘(源自编程之美)
- java动态代理(JDK和cglib)
- Configuration file: / etc / hostapd / hostapd.conf nl80211: 'nl80211' generic netlink not found
- 蓝桥杯 算法训练 安慰奶牛
- 最值钱的30句话,总有一句让你有收获
- Oracle-SQL-group by-报错:不是单组分组函数
- 泛型编程 实例 阶乘
- EGit学习指南
- N7100/GALAXY Note2 解决短信发件人实际发送短信时间
- 命令行模式下修改linux分辨率的快捷方法
- C++Primer 学习笔记
- TOJ-3135- Giant Screen
- iOS 计时器,排序
- Google Java Style
- Jquery获取和修改img的src值