#if 0
大家好,在这一类的文章中将会系统的介绍模板元编程的相关基础知识。最主要的是
这类文章的目的就是让不熟悉模板元的C++迷们尽快的进入到模板元的奇妙世界里面来,所
以每一篇文章都将只会讨论一个话题,尽可能的把这个话题说清楚明白就可以了。
好了,言归正传。大家都知道C++是一们计算机语言,这一点也没错,但是你知道C++
里面还包含了另外一种子语言么?呵呵,恐怕知道的人就不多了,会用的人就更少了。但
是既然经过了这么多年的发展,C++语言里面出现了这种子语言(模板)自然有它的根源的
,这一点并不是本文中将要讨论的,如果想了解C++的发展例程,可以参见相关的文献。
在本文中将要说明的问题是:为什么说C++模板是一种语言呢?
为了回答这个问题,首先需要考虑一下什么是计算机语言,关于这个精确的定义,很
多的计算机基础教程上都有,在这里我给出一种比较窄的定义:
能够在计算机上表达选择结构,循环结构,同时能够进行进行整数的四则运算的体系
就是一种计算机语言。
很显然,C++自然是一种计算机语言了,还有Basic,Fortran,Pascal等等都是计算机语
言。之所以讨论这么多的概念问题是为了说明:如何证明C++的模板语法是一种计算机语言
。又因为模板是C++语言的一个元素,所以又可以将C++模板语法称为C++的二级语言或者子
语言。在本文中将会通过使用模板分别实现整数四则运算,选择结构以及循环结构来证明
C++模板语法构成了一个完整的计算机语言。
另外特别值得注意的是,因为C++的模板语言是在编译器编译的时候完成的,所以又称
为静态语言,通常的C++语言又称为动态语言或者运行时语言。正是因为模板语言是在编译
期完成的,所以我们可以借助于这种编译期的计算实现代码自动生成的目的,从而实现C++
自动化编程。这是后续的文章中会详细讨论的。
首先看看,模板是如何完成编译期四则计算的。
#endif
#ifdef CODE1//编译期四则计算的示例代码
#include <iostream>
template<size_t i,size_t j> struct Add { enum{value = i+j}; };
template<size_t i,size_t j> struct Sub { enum{value = i-j}; };
template<size_t i,size_t j> struct Mul { enum{value = i*j}; };
template<size_t i,size_t j> struct Div { enum{value = i/j}; };
int main()
{
std::cout << "4+2=" << Add<4,2>::value << std::endl;
std::cout << "4-2=" << Sub<4,2>::value << std::endl;
std::cout << "4*2=" << Mul<4,2>::value << std::endl;
std::cout << "4/2=" << Div<4,2>::value << std::endl;
//为了证明上面的计算是在编译期进行的,我们编写下面的代码测试
//将模板值作为数组定义时使用的参数就可以证明是在编译期执行的计算:)
int a[Add<4,2>::value];//这么定义并没有错
int b[Sub<4,2>::value];//这么定义并没有错
int c[Mul<4,2>::value];//这么定义并没有错
int d[Div<4,2>::value];//这么定义并没有错
std::cout << sizeof(a)/sizeof(int) << std::endl;
std::cout << sizeof(b)/sizeof(int) << std::endl;
std::cout << sizeof(c)/sizeof(int) << std::endl;
std::cout << sizeof(d)/sizeof(int) << std::endl;
return 0;
}
#endif//CODE1
//程序运行结果如下所示:
/*******************************************************************************
4+2=6
4-2=2
4*2=8
4/2=2
6
2
8
2
*******************************************************************************/
#if 0
从代码CODE1中可以看出使用整型模板参数的模板是可以实现编译期计算的,在这里,
证明了这个计算过程是在编译期完成的。
好了,现在看看如何使用C++模板实现选择结构,见代码CODE2:
#endif
#ifdef CODE2//编译期实现选择的示例代码
#include <iostream>
template <bool Condition,class Then,class Else>
struct IF
{
typedef Then result;//将Then类型作为条件为真的返回值(返回值为类型)
};
template<class Then,class Else>
struct IF<false,Then,Else>
{
typedef Else result;//将Else类型作为条件为假的返回值(返回值为类型)
};
//为了测试这个IF选择结构,需要下面的两个类型定义:
struct True {static void Print(){std::cout << "真" << std::endl;}};
struct False{static void Print(){std::cout << "假" << std::endl;}};
int main()
{
IF<1==1,True,False>::result::Print();
IF<1!=1,True,False>::result::Print();
return 0;
}
#endif//CODE2
//程序运行结果如下所示:
/*******************************************************************************
真
假
*******************************************************************************/
#if 0
从CODE2中可以看出,这里操作的对象是类型,而CODE1中的操作对象是整数,到了这
里可以总结如下:C++模板元编程中的操作对象只有两种,一种是整形数,包括bool,char
,int,long,(signed unsigned)都可以,它们都可以当作整数使用,赋值和保存结果的
方式都是通过枚举变量来实现;另一种就是类型了,赋值和保存结果都是通过typedef来实
现的。例如CODE2中将IF的选择结果以Result的方式保存作为结果就是通过typedef实现的。
再来看看循环结构:
#endif
#ifdef CODE3//编译期实现循环的示例代码
#include <iostream>
//为了简单采用一个阶乘作为例子,因为如果用普通的C++语法来实现阶乘函数的话需要
//一个循环结构的,这里采用模板递归的方式实现了这种阶乘,也就实现了一种特殊的
//循环结构。
template<size_t n> struct Power {
enum{value=n*Power<n-1>::value}; //循环递归过程
};
template<> struct Power<0> {
enum{value=1}; //0的阶乘是1,也是循环的终止条件
};
int main()
{
int a[Power<5>::value];//同样用数组参数来判断是否在编译期完成计算
std::cout << sizeof(a)/sizeof(int) << std::endl;
return 0;
}
#endif//CODE3
//程序运行结果如下所示:
/*******************************************************************************
120
*******************************************************************************/
#if 0
从CODE3中我们可以看出Power是通过模板递归的方式实现循环的,而且这个循环过程
是在编译期完成的。到了这里可以总结出:C++模板元编程中实现循环的方式只有一种,那
就是模板递归实现循环。虽然这里的Power的循环不怎么直接,但是它确确实实是一个循环
结构,只不过是一个非常特殊的循环结构。实际上采用模板递归的方法可以实现普通C++语
法里面的for循环,while循环,do-while循环这些通用的循环结构。
到目前为止,已经成功的证明了C++模板是一个完整的计算机语言。既然是一门语言,
当然可以做许许多多的事情,这就在于每个人的发挥了。好了,在本文的最后给出一个通
用的LOOP循环作为本文的结束,这个LOOP循环可以进行简单的循环算法设计了,下面的例
子中将会说明这一点:
#endif
#ifdef CODE4
#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//CODE4
//程序运行结果如下所示:
/*******************************************************************************
0 1 2 3 4 5
*******************************************************************************/
#if 0
从CODE4中可以看出,这个静态LOOP循环是一个相对来说通用的循环代码,只需要将自
己的功能代码写入到一个函数(print)中就可以实现静态循环了,更重要的是,这个静态
LOOP循环实现了静态代码和动态代码的连接,因此用途更加广泛,主要可以用来产生代码
。关于如何产生代码,以及如何使用将是本类文章的后续文章讨论的内容。
本章完。
在下一章里面将会详细的讨论这里的LOOP循环并且一步一步的进行演化将这个LOOP循
环写得越来越通用,这里面是一个学习过程,也是理解这里的静态循环的一个理解过程。
(敬请关注!)
未完,待续...
#endif
C++自动化(模板元)编程基础与应用(1)
最新推荐文章于 2021-06-04 12:23:36 发布