#if 0
在上一篇文章的最后提到了一个相对来说通用一点的LOOP循环,下面还是将上一篇文
章中的LOOP循环代码复制如下:
#endif
#ifdef CODE1
#include <iostream>
template<size_t n> void print()
{//这里的n是编译期的结果,可以用来定义数组的
int a[n+1];//这么做是为了证明n是编译期常量
std::cout << sizeof(a)/sizeof(int)-1 << " " ;
}
template <size_t i>struct LOOP
{
static void execute(){LOOP<i-1>::execute();print<i>();}
};
template <>struct LOOP<0>//循环终止条件
{
static void execute(){print<0>();}
};
int main()
{
LOOP<5>::execute();
return 0;
}
#endif//CODE1
//程序运行结果如下所示:
/*******************************************************************************
0 1 2 3 4 5
*******************************************************************************/
#if 0
现在所需要考虑的问题是怎么将上面的print模板函数书写得更通用些,因为每定义一个
新的print函数就需要重新书写两个LOOP模板,为了避免这种重复代码得书写,在此很容易想
到的是将这个print模板函数作为模板参数传递,好了让我们开始新的尝试吧。具体得示例代
码如下所示:
#endif
#ifdef CODE2
#include <iostream>
//下面的两个模板就比CODE1里面的LOOP模板通用多了
template <template<size_t>class Function,size_t i> struct LOOP
{
static void execute()
{
LOOP<Function,i-1>::execute();
Function<i>::execute();
}
};
template <template<size_t>class Function> struct LOOP<Function,0>
{
static void execute()
{
Function<0>::execute();
}
};
//为了模板化必须将原来的输出函数做成一个模板结构体
template<size_t n> struct Function
{
static void execute()
{//这里的n是编译期的结果,可以用来定义数组的
int a[n+1];//这么做是为了证明n是编译期常量
std::cout << sizeof(a)/sizeof(int)-1 << " " ;
}
};
//下面是测试代码
int main()
{
LOOP<Function,5>::execute();
return 0;
}
#endif//CODE2
//程序运行结果如下所示:
/*******************************************************************************
0 1 2 3 4 5
*******************************************************************************/
#if 0
从CODE2的代码中可以看出,CODE2中的LOOP循环将CODE1中的print模板函数模板参数
化之后就使得CODE2中的LOOP更通用一些了,在使用的时候仅仅只是需要按照Function的规
范写一个模板结构就可以了,不必再书写重复结构的LOOP了,从而精简了使用时需要编写
的代码量。但是我们注意到结果并不复合STL的前闭后开的习惯,我们也不能很容易的理解
测试代码main函数中的LOOP<Function,n>的意义了,为了避免使用中的错误必须规定好它
的明确的意义:
(1)从0到n循环执行Function,并且是前闭后开的习惯
(2)将Function执行n次,每次的整型参数从0递增1
为了使CODE2中的LOOP循环表达的是这两个意义,必须对CODE2中的LOOP循环进行改写
改写候的代码如下所示:
#endif
#ifdef CODE3
#include <iostream>
//下面的两个模板就比CODE1里面的LOOP模板通用多了
template <template<size_t>class Function,size_t i> struct LOOP
{
static void execute()
{
LOOP<Function,i-1>::execute();
Function<i-1>::execute();
}
};
template <template<size_t>class Function> struct LOOP<Function,0>
{
static void execute(){}
};
//为了模板化必须将原来的输出函数做成一个模板结构体
template<size_t n> struct Function
{
static void execute()
{//这里的n是编译期的结果,可以用来定义数组的
int a[n+1];//这么做是为了证明n是编译期常量
std::cout << sizeof(a)/sizeof(int)-1 << " " ;
}
};
//下面是测试代码
int main()
{
//下面的这行代码可以按照上面的两种意义直观的理解为:
//(1)从0到5循环执行Function,范围[0,5)
//(2)将Function执行5次,每次的整型参数从0递增1
LOOP<Function,5>::execute();
return 0;
}
#endif//CODE3
//程序运行结果如下所示:
/*******************************************************************************
0 1 2 3 4
*******************************************************************************/
#if 0
从CODE3的运行结果来看确实满足了我们所需要表达的明确的意义,因此代码理解起来
就非常直观了。
从CODE3的代码中我们还是发现LOOP的起始参数固定为0,这一点实际上也是可以进一
步改进的。下面我们就来看看如何使得起始模板参数也可以指定的,见代码CODE4:
#endif
#ifdef CODE4
#include <iostream>
//加入一个外覆层来传递额外的模板参数
template <template<size_t>class Function,size_t start,size_t finish>
struct LOOP
{
static void execute()
{
LOOP_BODY<finish,true>::execute();
}
private:
//引入了一个布尔型的模板参数用来确定循环的终止条件
template <size_t i,bool> struct LOOP_BODY
{
static void execute()
{
LOOP_BODY<i-1,(i-1>start)>::execute();
Function<i-1>::execute();
}
};
//循环的终止语句,停止递归以结束循环
template <size_t i> struct LOOP_BODY<i,false>
{
static void execute(){}
};
};
//为了模板化必须将原来的输出函数做成一个模板结构体
template<size_t n> struct Function
{
static void execute()
{//这里的n是编译期的结果,可以用来定义数组的
int a[n+1];//这么做是为了证明n是编译期常量
std::cout << sizeof(a)/sizeof(int)-1 << " " ;
}
};
//下面是测试代码
int main()
{
//下面的这行代码可以直观的理解为:
//(1)从1到5循环执行Function,范围[1,5)
LOOP<Function,1,5>::execute();
//将两个输出分成两行输出
std::cout << std::endl;
//(1)从2到5循环执行Function,范围[2,5)
LOOP<Function,2,5>::execute();
return 0;
}
#endif//CODE4
//程序运行结果如下所示:
/*******************************************************************************
1 2 3 4
2 3 4
*******************************************************************************/
#if 0
从CODE4中的代码我们成功的通过添加了一层外敷类实现了循环的初始值设置,但是我们
还是应当注意CODE4中的循环步长并不能够指定,所以在这里我们通过类似的方法来实现步长
的指定。详细代码见CODE5所示:
#endif
#ifdef CODE5
#include <iostream>
//加入一个外覆层来传递额外的模板参数
template <template<size_t>class Function,size_t start,size_t finish,size_t step>
struct LOOP
{
static void execute()
{
//为了能够正确的计算出实际的循环终止变量,需要对给定的终止变量
//进行计算,以满足正确的循环语义
LOOP_BODY<(finish/step*step+start),true>::execute();
}
private:
//引入了一个布尔型的模板参数用来确定循环的终止条件
template <size_t i,bool> struct LOOP_BODY
{
static void execute()
{
LOOP_BODY<i-step,(i-step>start)>::execute();
Function<i-step>::execute();
}
};
//循环的终止语句,停止递归以结束循环
template <size_t i> struct LOOP_BODY<i,false>
{
static void execute(){}
};
};
//为了模板化必须将原来的输出函数做成一个模板结构体
template<size_t n> struct Function
{
static void execute()
{//这里的n是编译期的结果,可以用来定义数组的
int a[n+1];//这么做是为了证明n是编译期常量
std::cout << sizeof(a)/sizeof(int)-1 << " " ;
}
};
//下面是测试代码
int main()
{
//下面的这行代码可以直观的理解为:
//(1)从1到10循环执行Function,范围[1,10),步长2
LOOP<Function,1,10,2>::execute();
//将两个输出分成两行输出
std::cout << std::endl;
//(1)从2到10循环执行Function,范围[2,10),步长3
LOOP<Function,2,10,3>::execute();
//暂时还不能允许下面的逆向调用方式
//LOOP<Function,10,2,-3>::execute();
return 0;
}
#endif//CODE5
//程序运行结果如下所示:
/*******************************************************************************
1 3 5 7 9
2 5 8
*******************************************************************************/
#if 0
从CODE5的代码中可以看出明显存在一个缺陷:并不能够实现逆向的循环操作。这在类
型操作中并不是什么缺陷!因为在后续的章节的代码产生机制中并不需要逆向的循环操作
,所以为了使得本文尽量的简单,在这里并不讨论这个问题,这个问题留给读者思考,如
果在本类文章的后续章节中需要这个机制,那么我会在需要的地方实现之。
从CODE5的运行结果来看,CODE5的实现已经满足了我们日常编码的需要了,实际上用
这里介绍的方法还可以非常容易的实现许许多多的循环语句,包括FOR循环,WHILE循环等
等,但是需要注意的是:采用模板元编程主要是用来实现自己的功能代码的,使用这里介
绍的循环代码已经可以满足后面进行代码生成的需要了。所以本文的静态循环代码介绍也
可以到此打住了,不过各位有兴趣的话,可以和我联系,我非常愿意和您讨论这些话题:)
本章完。
在下一章里将会介绍代码的生成的机制,并通过解决一些简单的问题来说明代码生成
为什么可以实现自动化过程。(敬请关注!)
未完,待续...
#endif
C++自动化(模板元)编程基础与应用(2)
最新推荐文章于 2021-06-04 12:23:36 发布