C++自动化(模板元)编程基础与应用(3)

#if 0

在前面的两章里面讨论了C++模板元作为C++的一门二级语言的问题,并给出了常用的
程序设计语言的语素的实现,是一个完备的体系。总的来说,前面的章节里面是采用了下
面的方法来实现这些语素的:

(1)整数计算结果通过enum变量进行保存

(2)类型计算结果通过typedef进行保存

(3)?:运算符可用来实现静态整型表达式的选择功能

(4)模板特化可用来实现静态类型表达式的选择功能

(5)模板递归可用来实现静态循环,循环变化元素只能够是整数

(6)通过整数可以映射到类型,所以循环变化元素也可以间接为类型

这一章里面我们将要讨论另外的问题,所采用的方法也是这些方法。那么本文将要讨
论的问题是:

如何实现类型循环,也就是上面总结出来的第(6)种技巧。

关于这一点的讨论,我认真参考了<<Modern C++ Design>>一书的Typelist,在本文中
将会以cons来表达类型列表的概念,并对<<Modern C++ Design>>一书的Typelist相关的操
作进行精简,得到我们将会在生成代码的过程中使用的模板元函数。不用的根本不会考虑
,所以为了使撤销和重做库尽可能的独立些,所以我不采用Loki库,这样使得该撤销和重
做库的安装比较简单。

为此,首先实现一个类型串类型名叫cons,代码如下:

#endif

#ifdef CODE_NOTE
//cons的实现,采用和STL类似的类型命名方式
template <class FirstType,class SecondType>
struct cons
{
typedef FirstType first_type;
typedef SecondType second_type;
};
//有了上面的cons的实现,现在就可以很容易的将类型放入到这个串中了:
typedef cons<char,
cons<int,
cons<short,
cons<long,
cons<float,
double> > > > > CONS;
//上面的代码定义了一个6中基本类型作为元素的类型串CONS,那么该怎么实现对上面的类
//型的操作呢?仔细想想C语言里面的字符串是如何处理字符串的终结的啊!呵呵可能你已
//经想到了,需要一个特殊的终结符,对了,为了能够操作上面的类型容器我们需要定义
//一个终结符类型:
struct null_type;
//有了上面的null_type,现在的类型容器CONS重新表述如下:
typedef cons<char,
cons<int,
cons<short,
cons<long,
cons<float,
cons<double,
null_type> > > > > > CONS;
#endif//CODE_NOTE

#if 0

有了上面的cons类型和终结符已经可以用来表达类型串的概念了,既然有了类型串,
那就应该有类型串的相关操作,这里我们首先考虑的是,这些操作将会应用到什么地方?
考虑一下如何使用前面的LOOP静态循环来遍历cons串中的所有类型呢?很显然通过本文开
头对前文的总结(5)我们知道静态LOOP循环可以变化的只能是整数,那么很自然的为了能够
实现类型遍历必须实现整数和类型的映射和反映射元函数。一种直接的方式就是根据索引
值得到cons串中的每一个类型,这样就需要至少两个元函数来完成这种循环,这两个元函
数分别是:

(a)length元函数,用来获得cons串的长度

(b)type元函数,用来根据索引值得到相应的cons串在该位置的类型

有了上面的两个元函数就可以很方便的使用LOOP静态循环来实现类型遍历的过程了。
现面来看看如何实现这两个元函数:在给出这两个元函数的实现之前,为了明确起见,需
要准确定义这两个元函数的返回值的意义

(length)根据具体的CONS类型得到的是cons串的长度,这个长度指的是不包括类型串
结束符的元素个数,这一点和C字符串的strlen库函数的行为类似。

(type)根据具体的CONS类型和一个给定的索引值得到一个类型,指的是cons类型串中
的指定索引值的位置的类型,这个索引值符合C语言的规范,是从0开始编号的。

在给出具体的这两个元函数的实现之前需要将前面的章节中的命名规范说明一下:

(A)如果元函数的返回值为整数,那么返回值名称命名为value

(B)如果元函数的返回值为类型,那么返回值名称命名为result

好了,现在可以看看如何实现这两个元函数了:

#endif

#ifdef CODE_NOTE
//length元函数的实现
template<class Type>struct length;
template<>struct length<null_type>
{//返回值为整数,命名为value
enum{value=0};
};
template<class FirstType,class SecondType>
struct length<cons<FirstType,SecondType> >
{//返回值为整数,命名为value
enum{value=1+length<SecondType>::value};
};
//type元函数的实现
template<class Cons,size_t index>struct type;
template<class FirstType,class SecondType>
struct type<cons<FirstType,SecondType>,0>
{//返回值为类型,命名为result
typedef FirstType result;
};
template<class FirstType,class SecondType,size_t i>
struct type<cons<FirstType,SecondType>,i>
{//返回值为类型,命名为result
typedef typename type<SecondType,i-1>::result result;
};
#endif//CODE_NOTE

#if 0

两个需要的元函数已经成功的给出了,如果有什么不清楚的地方也可以参见<<Modern
C++ Design>>一书的Typelist的Length元函数和TypeAt元函数的解释,基本上是一样的,
这里不在进行过多的解释。在这里我们所重视的是如何使用这两个元函数来实现我们的类
型遍历算法。现咱万事具备了,可以开始本章的中心内容:实现类型的遍历算法!不过在
给出具体的代码之前还需要做一件事情,那就是将之前的代码保存到一个文件中,为了统
一起见,我们就先将这个文件名命名为meta.h吧!该文件的详细内容在本文的最后给出。
现在看一下如何实现我们的类型遍历算法吧,见CODE1所示:

#endif

#ifdef CODE1
#include <iostream>
#include "meta.h"//该文件的具体内容见本文的最后
namespace xcl = pandaxcl;//缩写名字空间
//为了能够测试type元函数需要定义下面的一些额外的测试模板
template<class T> struct traits;
template<> struct traits<char >{static const char*name(){return "char";}};
template<> struct traits<int >{static const char*name(){return "int";}};
template<> struct traits<short >{static const char*name(){return "short";}};
template<> struct traits<long >{static const char*name(){return "long";}};
template<> struct traits<float >{static const char*name(){return "float";}};
template<> struct traits<double>{static const char*name(){return "double";}};
//必须外加一层包裹层来传递额外的类型参数
template <class T> struct Config
{
template<size_t i> struct Function
{
static void execute()
{
//你的代码在这里编写
typedef typename xcl::type<T,i>::result CT;//当前类型的意思
std::cout << i << " : " << traits<CT>::name() << std::endl;
}
};
};
int main()
{
typedef xcl::cons<char,
xcl::cons<int,
xcl::cons<short,
xcl::cons<long,
xcl::cons<float,
xcl::cons<double,
xcl::null_type> > > > > > CONS;
std::cout << "CONS类型串的长度为:" << xcl::length<CONS>::value << std::endl;
xcl::LOOP<Config<CONS>::Function,0,xcl::length<CONS>::value,1>::execute();
return 0;
}
#endif//CODE1

//该程序的运行结果为:
/*******************************************************************************
CONS类型串的长度为:6
0 : char
1 : int
2 : short
3 : long
4 : float
5 : double
*******************************************************************************/

#if 0

从CODE1中的代码可以看出,我们已经成功的实现了类型的循环遍历。之所以需要实现
这种功能是因为这种功能能够在下一章中对自动生成的代码执行任意的操作,这一点在自
动生成代码上非常重要,如果这一点没有实现,C++模板元自动生成的代码和C宏生成的代
码相比将不会有什么神奇指出。这也是我将这段内容安排在这一章的主要原因。可能您还
没有认识到这里的代码的重要性,不过这没什么关系,我会在后续的章节中详细说明这里
的类型遍历的使用过程,并实现动态代码和静态代码的连接。这样之后您自然就会了解本
章的意义所在了:)

下面给出CODE1中的头文件meta.h的内容如下:

#endif
#ifdef CODE_NOTE
#pragma once
namespace pandaxcl{
//
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类型作为条件为假的返回值(返回值为类型)
};
//
//
加入一个外覆层来传递额外的模板参数
template <template<size_t>class Function,size_t start,size_t finish,size_t step>
struct LOOP
{
//为了能够正确的计算出实际的循环终止变量,需要对给定的终止变量
//进行计算,以满足正确的循环语义
enum{real_finish=(finish/step*step+start)};
static void execute()
{
LOOP_BODY<real_finish,true>::execute();
}
//下面的这个模板函数是为了能够实现静态代码和动态代码连接
template <class EnvironmentType>
static void execute(EnvironmentType&e)
{
LOOP_BODY<real_finish,true>::execute(e);
}
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 <class EnvironmentType>
static void execute(EnvironmentType&e)
{
LOOP_BODY<i-step,(i-step>start)>::execute(e);
Function<i-step>::execute(e);
}
};
//循环的终止语句,停止递归以结束循环
template <size_t i> struct LOOP_BODY<i,false>
{
static void execute(){}
//下面的这个模板函数是为了能够实现静态代码和动态代码连接
template <class EnvironmentType>
static void execute(EnvironmentType&e){}
};
};
//为了模板化必须将原来的输出函数做成一个模板结构体
//template<size_t n> struct Function
//{
// static void execute()
// {
// //你的代码在这里编写
// }
//};
//
//
//cons的实现,采用和STL类似的类型命名方式
template <class FirstType,class SecondType>
struct cons
{
typedef FirstType first_type;
typedef SecondType second_type;
};
struct null_type;//类型串终结符
//下面是两个为了实现静态类型循环所需要的静态元函数
//length元函数的实现
template<class Type>struct length;
template<>struct length<null_type>
{//返回值为整数,命名为value
enum{value=0};
};
template<class FirstType,class SecondType>
struct length<cons<FirstType,SecondType> >
{//返回值为整数,命名为value
enum{value=1+length<SecondType>::value};
};
//type元函数的实现
template<class Cons,size_t index>struct type;
template<class FirstType,class SecondType>
struct type<cons<FirstType,SecondType>,0>
{//返回值为类型,命名为result
typedef FirstType result;
};
template<class FirstType,class SecondType,size_t i>
struct type<cons<FirstType,SecondType>,i>
{//返回值为类型,命名为result
typedef typename type<SecondType,i-1>::result result;
};
//
}//namespace pandaxcl{
#endif//CODE_NOTE
#if 0

从上面的meta.h文件中我们还可以看出,LOOP静态循环代码里面比前一篇文章中的
LOOP循环多了一些额外的代码,这是为了能够实现静态代码和动态代码的连接的,这种连
接通常是通过函数参数的形式实现的。至于为什么需要这一点将会在下一篇文章的代码自
动生成一章中进行讨论。(敬请关注!)

本章完。

未完,待续...

#endif
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值