#if 0
在上一章里面讨论了复合对象的问题。RoundRectangle类(b)方案是一个复合类方案,
从上一章的内容我们可以看出虽然实现了一个RoundRectangle类确实是一个复合类,但是
实现复合类是一个比较繁琐的事情,对于一个程序里面有很多这种类的情况,那么前一章
里面的编码过程将会是一个非常繁琐的体力劳动。在这一章里面将使用模板元编程将这种
繁琐的体力劳动自动化。
在给出实现之前我们还是先把问题弄清楚!所以必须先回答下面的几个问题:
(1)自动化的目标是什么?关于这个问题,从前一章可以看出:很显然将要给出一个通
用的复合对象类。那么这个最终的类名,我命名为:“compound”,因为这个词具有化合
物的意思。学过高中化学的都知道,化合物可以是一种单质。很显然这里的复合对象类自
身是一个完备的整体,这一点和单质的概念有点类似:)。
(2)这个复合对象类的输入参数是什么?从前一章可以得出:传入的参数当然是各个属
性的类型信息串。这种类型串正好可以使用模板元编程基础与应用的cons类型串来实现。
(3)这个复合对象类具备有那些操作?从前一章可以看出:复合对象类很显然应该具备
有三种操作,分别是创建(create)、修改(modify)和删除(remove)。其中创建操作将会在
复合对象创建的同时把所有的属性类型的对象也创建一份;修改操作则可以直接修改每一
个属性对象,这是通过属性类型的静态转型来实现的;删除操作将会在复合对象删除之前
把所有的属于该复合对象的属性对象全部删除。
(4)这个复合对象类的操作应该遵守什么约定?这一点需要特殊说明,为了使得本章所
介绍的复合对象类尽可能的简单而且通用,在这里我直接采用可以通过索引号访问自动生
成的变量的代码产生类scatter,这一点可以参见我得“C++自动化(模板元)编程基础与应
用”系列文章。这样之后就可以直接使用许许多多的C++模板元高级技术来实现我们要求的
功能啦:)。
现在问题已经比较明了了,下面看看CODE1的实现和测试代码:
#endif
#ifdef CODE1
#include <iostream>
#include "command.h"
#include "center.h"
////////////////////////////////////////////////////////////////////////////////
//复合对象类的实现
#include "meta.h"//模板元编程基础与应用讨论的内容
#include "identifier.h"//复合对象类必须使用这个类
namespace pandaxcl{
//scatter产生代码需要的基元模板,用来生成属性
template <class T> struct compound_unit
{
//通过下面的代码就可以解释为什么前面在讨论标识号类的时候必须采用
//和类型相关的标识号,而不能够有通用的标识号类了:)
identifier<T> ID;//属性对象的标识号
//在上面的标识号模板中使用默认的第二个模板参数类型long,这一点将
//会在后续的进行弹性相关的讨论的文章中讨论。在这里就是先要让代码
//能够正常运行起来:),通常来说只需要使用默认的参数就可以正常使用
//了,但是对于特殊的情况也不能不进行讨论:)。
};
//利用scatter来生成代码创建自动化类,并通过模板元编程来实现操作代码的自动化
//这样之后这整个类就成了名副其实的自动化类了:)
template<class Cons>class compound
:public scatter<Cons,pandaxcl::compound_unit>
{
public:
typedef Cons cons_type;
typedef scatter<Cons,pandaxcl::compound_unit> scatter_type;
//复合对象的创建函数的自动化实现
template <class ControlType,class CID>
static void create(ControlType&C,const CID&ID)
{
typedef container<CID,compound> TCT;//复合对象容器类型
compound tmp;//定义一个临时的复合类对象
C.record();
//自动化创建所有的子图元
ENVIRONMENT<ControlType> e(C,tmp);
LOOP<CREATE,0,length<cons_type>::value,1>::execute(e);
//然后创建自身,由于create命令和这里的create函数同名,所以
//用名字空间进行限制选择create命令
C.execute(new pandaxcl::create<TCT>(C,ID,tmp));
C.stop();
}
//下面的函数是用来修改复合对象的属性的修改函数
template <size_t i,class PropertyType,class ControlType,class CID>
static void modify(ControlType&C,const CID&ID,const PropertyType&OM)
{
typedef container<CID,compound> TCT;//复合对象容器类型
typedef identifier<PropertyType> PID;//属性对象使用的标识符类型
typedef container<PID,PropertyType> PCT;//属性对象使用的容器类型
typedef compound_unit<PropertyType> UTT;//确保每行代码不至于过长
const compound &S = static_cast<TCT&>(C).reference(ID);
const UTT &P = static_cast<const UTT&>(field<i>(S));
//由于modify命令和这里的midify函数同名,所以用名字空间
//进行限制选择modify命令
C.execute(new pandaxcl::modify<PCT>(C,P.ID,OM));
}
//复合对象的删除函数的自动化实现
template <class ControlType,class CID>
static void remove(ControlType&C,const CID&ID)
{
//因为删除复合对象是一步操作,所以需要将所有的子元素的删除合并
//成为一个复合命令,使之表现的比较象简单对象的删除操作一样。
typedef container<CID,compound> TCT;//复合对象容器类型
const compound&S = static_cast<TCT&>(C).reference(ID);
C.record();
//自动化删除所有的子图元
ENVIRONMENT<ControlType> e(C,S);
LOOP<REMOVE,0,length<cons_type>::value,1>::execute(e);
//然后删除自身,由于remove命令和这里的remove函数同名,所以
//用名字空间进行限制选择remove命令
C.execute(new pandaxcl::remove<TCT>(C,ID));
C.stop();
}
private:
//CREATE和REMOVE都需要传入的动态参数结构
template<class ControlType> struct ENVIRONMENT
{
typedef ControlType control_type;
ENVIRONMENT(ControlType&C,const compound&c)
:_control(C),_compound(c){}
ControlType &_control;//控制面板
const compound &_compound;//复合对象
};
//自动化的创建所有的属性对象
template<size_t i> struct CREATE
{
template<class EnvironmentType>
static void execute(EnvironmentType&e)
{
//你的代码在这里编写
typedef typename type<cons_type,i>::result CT;
typedef identifier<CT> PID;//属性对象使用的标识符类型
typedef container<PID,CT> PCT;//属性对象使用的容器类型
typedef compound_unit<CT> UTT;//确保每行代码不至于过长
const UTT &v = static_cast<const UTT&>(field<i>(e._compound));
typename EnvironmentType::control_type &C=e._control;
C.execute(new pandaxcl::create<PCT>(C,v.ID,CT()));
}
};
//自动化的删除所有的属性对象
template<size_t i> struct REMOVE
{
template<class EnvironmentType>
static void execute(EnvironmentType&e)
{
//你的代码在这里编写
typedef typename type<cons_type,i>::result CT;
typedef identifier<CT> PID;//属性对象使用的标识符类型
typedef container<PID,CT> PCT;//属性对象使用的容器类型
typedef compound_unit<CT> UTT;//确保每行代码不至于过长
const UTT &v = static_cast<const UTT&>(field<i>(e._compound));
typename EnvironmentType::control_type &C=e._control;
C.execute(new pandaxcl::remove<PCT>(C,v.ID));
}
};
};
}//namespace pandaxcl{
////////////////////////////////////////////////////////////////////////////////
//下面的测试代码和前一章的类似,但是是采用上面的复合类模板来自动化的实现前面的
//RoundRectangle类!使用这种方法还可以用来批量自动生成所有的这种类型的复合类,
//看你的发挥了:)。
namespace xcl = pandaxcl;//名字空间重命名
//矩形类
class Rectangle
{
public:
Rectangle():_x(0),_y(0),_width(20),_height(10){}
Rectangle(int x,int y,int w,int h):_x(x),_y(y),_width(w),_height(h){}
private:
int _x,_y,_width,_height;
//下面的函数仅仅是为了输出信息而准备的
friend std::ostream&operator<<(std::ostream&s,Rectangle&o)
{
s << "(" << o._x << "," << o._y << "," << o._width << "," << o._height << ")" ;
return s;
}
};
//圆形类
class Circle
{
public:
Circle():_x(0),_y(0),_radius(20){}
Circle(int x,int y,int r):_x(x),_y(y),_radius(r){}
private:
int _x,_y,_radius;
//下面的函数仅仅是为了输出信息而准备的
friend std::ostream&operator<<(std::ostream&s,Circle&o)
{
s << "(" << o._x << "," << o._y << "," << o._radius << ")" ;
return s;
}
};
//圆角矩形类
typedef xcl::cons<Rectangle,
xcl::cons<Circle,//重复类型
xcl::cons<Circle,//重复类型
xcl::cons<Circle,//重复类型
xcl::cons<Circle,//重复类型
xcl::null_type> > > > >ROUNDRECTANGLE;
//由上面的类型串自动生成圆角矩形类
typedef xcl::compound<ROUNDRECTANGLE> RoundRectangle;
//需要说明的是下面所有的标识号的单元类型都采用默认值,在这里不可以采用其它的元素
//这一点将会在后续的文章中讨论。
typedef xcl::identifier<Rectangle > RID;//矩形类标识号类型
typedef xcl::identifier<Circle > CID;//圆形类标识号类型
typedef xcl::identifier<RoundRectangle> RRID;//圆角矩形类标识号类型
//下面的函数仅仅是为了输出信息而准备的,实际上下面的这个函数也是可以实现
//自动化的,不过这里为了简单起见,特殊情况特殊对待了:)。
std::ostream&operator<<(std::ostream&s,RoundRectangle&o)
{
s << "R:[" << std::hex << xcl::field<0>(o).ID << "] " ;
s << "C:[" << std::hex << xcl::field<1>(o).ID << "] " ;
s << "C:[" << std::hex << xcl::field<2>(o).ID << "] " ;
s << "C:[" << std::hex << xcl::field<3>(o).ID << "] " ;
s << "C:[" << std::hex << xcl::field<4>(o).ID << "] " ;
return s;
}
//观察容器的内容而准备的
template <class Container>
void display(const char*str,Container&c)
{
typedef typename Container::value_type value_type;
struct X
{
static void print(value_type&v)
{
std::cout.setf(std::ios::showbase);//显示16进制的0x前缀
std::cout << "(" <<std::hex<< v.first << "," ;
std::cout << std::dec << v.second << ") ";
}
};
//输出提示信息,并输出容器中的元素数量
std::cout << str << "[" << std::dec << c.size() << "] ";
std::for_each(c.begin(),c.end(),X::print);//输出容器中的所有的标识号和对象信息
std::cout << std::endl;
}
//需要一个控制面板类,实际上下面的这个类也是可以自动化的,不过这是后话:)
class Control
:public xcl::center
,public xcl::container<RID ,Rectangle >
,public xcl::container<CID ,Circle >
,public xcl::container<RRID,RoundRectangle>
{
public:
//下面的函数是输出该控制面板对象的相关信息的
void display(const char*str)
{
typedef xcl::container<RID ,Rectangle > RC;
typedef xcl::container<CID ,Circle > CC;
typedef xcl::container<RRID,RoundRectangle> RRC;
std::cout << "----------"<<str<<"----------" <<std::endl;
std::cout << "Undo:[" << std::dec << xcl::center::undo_type::size() << "] " ;
std::cout << "Redo:[" << std::dec << xcl::center::redo_type::size() << "] " ;
std::cout << std::endl ;
::display("矩形容器 :",static_cast<RC&>(*this));
::display("圆形容器 :",static_cast<CC&>(*this));
::display("圆角矩形容器:",static_cast<RRC&>(*this));
std::cout << "=========="<<str<<"==========" <<std::endl;
}
};
int main()
{
//首先应用程序中必须有一个全局的控制面板类对象
Control C;
RRID ID;//复合对象的标识号对象
//模拟创建复合对象
RoundRectangle::create(C,ID);
C.display("创建复合对象");
C.undo();//撤销一步
C.display("撤销一步");
C.redo();//重做一步
C.display("重做一步");
//模拟修改复合对象
C.record();
RoundRectangle::modify<0>(C,ID,Rectangle(1,1,200,100));
RoundRectangle::modify<1>(C,ID,Circle(1 ,1 ,5));
RoundRectangle::modify<2>(C,ID,Circle(201,1 ,5));
RoundRectangle::modify<3>(C,ID,Circle(201,101,5));
RoundRectangle::modify<4>(C,ID,Circle(1 ,101,5));
C.stop();
C.display("修改复合对象的属性");
C.undo();//撤销一步
C.display("撤销一步");
C.redo();//重做一步
C.display("重做一步");
//模拟删除复合对象
RoundRectangle::remove(C,ID);
C.display("删除复合对象");
C.undo();//撤销一步
C.display("撤销一步");
C.redo();//重做一步
C.display("重做一步");
return 0;
}
#endif//CODE1
////////////////////////////////////////////////////////////////////////////////
//该程序运行结果如下:
/*******************************************************************************
----------创建复合对象----------
Undo:[1] Redo:[0]
矩形容器 :[1] (0x1,(0,0,20,10))
圆形容器 :[4] (0x1,(0,0,20)) (0x2,(0,0,20)) (0x3,(0,0,20)) (0x4,(0,0,20))
圆角矩形容器:[1] (0x1,R:[0x1] C:[0x1] C:[0x2] C:[0x3] C:[0x4] )
==========创建复合对象==========
----------撤销一步----------
Undo:[0] Redo:[1]
矩形容器 :[0]
圆形容器 :[0]
圆角矩形容器:[0]
==========撤销一步==========
----------重做一步----------
Undo:[1] Redo:[0]
矩形容器 :[1] (0x1,(0,0,20,10))
圆形容器 :[4] (0x1,(0,0,20)) (0x2,(0,0,20)) (0x3,(0,0,20)) (0x4,(0,0,20))
圆角矩形容器:[1] (0x1,R:[0x1] C:[0x1] C:[0x2] C:[0x3] C:[0x4] )
==========重做一步==========
----------修改复合对象的属性----------
Undo:[2] Redo:[0]
矩形容器 :[1] (0x1,(1,1,200,100))
圆形容器 :[4] (0x1,(1,1,5)) (0x2,(201,1,5)) (0x3,(201,101,5)) (0x4,(1,101,5))
圆角矩形容器:[1] (0x1,R:[0x1] C:[0x1] C:[0x2] C:[0x3] C:[0x4] )
==========修改复合对象的属性==========
----------撤销一步----------
Undo:[1] Redo:[1]
矩形容器 :[1] (0x1,(0,0,20,10))
圆形容器 :[4] (0x1,(0,0,20)) (0x2,(0,0,20)) (0x3,(0,0,20)) (0x4,(0,0,20))
圆角矩形容器:[1] (0x1,R:[0x1] C:[0x1] C:[0x2] C:[0x3] C:[0x4] )
==========撤销一步==========
----------重做一步----------
Undo:[2] Redo:[0]
矩形容器 :[1] (0x1,(1,1,200,100))
圆形容器 :[4] (0x1,(1,1,5)) (0x2,(201,1,5)) (0x3,(201,101,5)) (0x4,(1,101,5))
圆角矩形容器:[1] (0x1,R:[0x1] C:[0x1] C:[0x2] C:[0x3] C:[0x4] )
==========重做一步==========
----------删除复合对象----------
Undo:[3] Redo:[0]
矩形容器 :[0]
圆形容器 :[0]
圆角矩形容器:[0]
==========删除复合对象==========
----------撤销一步----------
Undo:[2] Redo:[1]
矩形容器 :[1] (0x1,(1,1,200,100))
圆形容器 :[4] (0x1,(1,1,5)) (0x2,(201,1,5)) (0x3,(201,101,5)) (0x4,(1,101,5))
圆角矩形容器:[1] (0x1,R:[0x1] C:[0x1] C:[0x2] C:[0x3] C:[0x4] )
==========撤销一步==========
----------重做一步----------
Undo:[3] Redo:[0]
矩形容器 :[0]
圆形容器 :[0]
圆角矩形容器:[0]
==========重做一步==========
*******************************************************************************/
////////////////////////////////////////////////////////////////////////////////
#if 0
从上面的代码我们可以看出,已经成功的实现了复合类的自动生成。只需要修改相应的
输入类型串就可以自己定义出许许多多的复合类出来。这一点非常的方便,但是我们还是可
以看出,上面的复合类的创建、修改和删除过程和前面的简单对象有所不同。复合类是使用
静态成员函数实现的三个操作,而简单对象是直接使用基本命令完成的操作,这里面就有着
不同的使用规则。实际上在后面,还要对这种使用规则进行自动化,使得这个撤销重做库给
出尽可能少的使用规则,所有的注意事项都由库自动化的完成。为了以后使用的方便,这个
compound复合类模板将会保存到文件“compound.h”中。在本文中使用了代码自动生成技术
,关于这一点可以参见“C++自动化(模板元)编程基础与应用”系列文章。
本章完。
从上面的compound类的实现可以看出,对于派生自compound的复合类,是不可以直接
使用上面的三个静态函数来完成复合类对象的撤销和重做的,因此将会在下一章里面讲解
:派生这里的符合类。(敬请关注!)
上一篇:撤销和重做(Undo和Redo)的C++完美实现(6)
下一篇:撤销和重做(Undo和Redo)的C++完美实现(7-2)
我的博客:http://blog.csdn.net/pandaxcl/
#endif
#if CODE_NOTE//附录:本文使用的meta.h如下:
#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 i> 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;
};
//index元函数根据类型得到类型串中该类型位置
template<class Cons,class Test>struct index;
template<class Test> struct index<null_type,Test>
{
enum{value=-1};
};
template<class T,class Test> struct index<cons<Test,T>,Test>
{
enum{value=0};
};
template<class H,class T,class Test> struct index<cons<H,T>,Test>
{
private:
enum{temp=index<T,Test>::value};
public:
enum{value=(temp==-1?-1:1+temp)};
};
//////////////////////////////////////////////////////////////////////
//下面是实现代码自动生成的模板元函数,主要参考了Loki的代码
//为了撤销和重做库的独立性,将该功能从Loki库中提取出来
//template<class T,template<class>class Unit>
//struct scatter : public Unit<T>
//{
//};
//template<class H,class T,template<class>class Unit>
//struct scatter<cons<H,T>,Unit>
// : public scatter<H,Unit>
// , public scatter<T,Unit>
//{
// typedef cons<H,T> cons_type;
//};
////下面的null_type参看前一章中的代码
//template<template<class>class Unit>
//struct scatter<null_type,Unit>
//{
//};
////////////////////////////////////////////////////////////
//下面的这个产生代码的格式还可以使用索引号得到基元对象
template<size_t i,class T,template<class>class Unit>
struct scatter_helper : public Unit<T>
{
};
template<size_t i,class H,class T,template<class>class Unit>
struct scatter_helper<i,pandaxcl::cons<H,T>,Unit>
: public scatter_helper<i,H,Unit>
, public scatter_helper<i+1,T,Unit>
{
typedef pandaxcl::cons<H,T> cons_type;
};
//下面的null_type参看前一章中的代码
template<size_t i,template<class>class Unit>
struct scatter_helper<i,pandaxcl::null_type,Unit>
{
};
template <class Cons,template<class>class Unit>
struct scatter:public scatter_helper<0,Cons,Unit>
{
typedef Cons cons_type;
};
//下面的函数用来根据类型索引号来得到相应的基元类型
template <size_t i,class Cons,template<class>class Unit>
scatter_helper<i,typename pandaxcl::type<Cons,i>::result,Unit>&
field(scatter<Cons,Unit>&obj)
{
typedef typename pandaxcl::type<Cons,i>::result CT;
typedef scatter_helper<i,CT,Unit> RT;
return static_cast<RT&>(obj);
};
template <size_t i,class Cons,template<class>class Unit>
const scatter_helper<i,typename pandaxcl::type<Cons,i>::result,Unit>&
field(const scatter<Cons,Unit>&obj)
{
typedef typename pandaxcl::type<Cons,i>::result CT;
typedef scatter_helper<i,CT,Unit> RT;
return static_cast<const RT&>(obj);
};
//////////////////////////////////////////////////////////////////////
}//namespace pandaxcl{
#endif//CODE_NOTE
发表于 @ 2006年04月20日 09:43:00|评论(loading...)|编辑