游戏开发论坛

 找回密码
 立即注册
搜索
查看: 2689|回复: 9

大家新年好,有个模板的问题想请教

[复制链接]

15

主题

129

帖子

129

积分

注册会员

Rank: 2

积分
129
QQ
发表于 2007-2-23 11:50:00 | 显示全部楼层 |阅读模式
想写一个Undo和Redo的功能,因为参数最多也就是5个,准备自己写。可是无法编译过去,因为有点害怕模板,平时用的也少,一到关键时刻就歇菜了。
在vs2005中编译的错误如下:
error C2955: “NmFnCall”: 使用类 模板 需要 模板 参数列表
错误的位置: NmFnCall* fp = reinterpret_cast<NmFnCall*>(CreateNFN(f));
//-----------------------------------------------------------------------------------------
//基类
//-----------------------------------------------------------------------------------------
template<class R>
class NmFnCall
{
public:
        virtual R Run() const = 0;
};
//-----------------------------------------------------------------------------------------
//无参的函数指针
//-----------------------------------------------------------------------------------------
template<class R>
class NormalFnNon:public NmFnCall<R>
{
public:
        explicit NormalFnNon( R (*p)() ):fp(p){}
        R Run()  const{return (*fp)();}
private:
        R (*fp)();
};
template<class R>
NormalFnNon<R>* CreateNFN( R (*p) )
{
        return new NormalFnNon<R>(p);
}
/*
其他免
*/
//-----------------------------------------------------------------------------------------
//实现
//-----------------------------------------------------------------------------------------
class RUdo
{
public:
template<class R>
        bool Pop()
        {
                if( _fn_call.empty() ) return false;
                _fn_call.top()->Run();
                _fn_call.pop();
                return true;
        }
        template<class R>
        void Push( R(*f)() )
        {       
                NmFnCall* fp = reinterpret_cast<NmFnCall*>(CreateNFN(f));
                _fn_call.push( fp );
        }
private:
        std::stack<NmFnCall*>        _fn_call;        //函数调用
};

15

主题

129

帖子

129

积分

注册会员

Rank: 2

积分
129
QQ
 楼主| 发表于 2007-2-24 01:25:00 | 显示全部楼层

Re: 大家新年好,有个模板的问题想请教

改着改着发现能用了,现在的代码如下.可还有个隐忧,我也说不清楚.大概就是实现的那个地方,typedef NmFnCall<T> Call;感觉返回类型等于一开始就确定了,还是不太符合要求.得再考虑考虑,只能明儿接着改了
//-----------------------------------------------------------------------------------------
//基类
//-----------------------------------------------------------------------------------------
template<class R>
class NmFnCall
{
public:
        virtual R Run() = 0;
};

//-----------------------------------------------------------------------------------------
//无参的函数指针
//-----------------------------------------------------------------------------------------
template<class R>
class NormalFnNon:public NmFnCall<R>
{
public:
        explicit NormalFnNon( R (*p)() ):fp(p){}
        R Run() {return (*fp)();}
private:
        R (*fp)();
};
template<class R>
NormalFnNon<R>* CreateNFNon( R (*p)() )
{
        return new NormalFnNon<R>(p);
}
//-----------------------------------------------------------------------------------------
//实现
//-----------------------------------------------------------------------------------------
template<class T>
class RUdo
{
public:
        typedef NmFnCall<T> Call;
        bool Empty() const{return _fn_call.empty();}
        bool Pop()
        {
                if( _fn_call.empty()==true ) return false;
                _fn_call.top()->Run();
                _fn_call.pop();
                return true;
        }
        template<class R>
        void Push( R(*f)() )
        {       
                _fn_call.push( CreateNFNon(f) );
        }
private:
        std::stack<Call*>        _fn_call;        //函数调用
};

#endif

5

主题

44

帖子

44

积分

注册会员

Rank: 2

积分
44
发表于 2007-2-24 11:35:00 | 显示全部楼层

Re:大家新年好,有个模板的问题想请教

牛人把你的测试代码贴一下

int redoint(){
        printf("redo int\n");
        return 0;
}
float redofloat(){
        printf("redo float\n");
        return 0;
}

int undo(){
        printf("undo\n");
        return 0;
}
void main(){
        typedef NormalFnNon<int> intfunc;
        typedef NormalFnNon<float> floatfunc;
        intfunc r1(&redoint);
        floatfunc r2(&redofloat);

        r1.Run();
        r2.Run();

        //RUdo<int>  list;
}
只能做到这部,你那个RUdo怎么实例化的贴个例子给看看先啊

5

主题

44

帖子

44

积分

注册会员

Rank: 2

积分
44
发表于 2007-2-24 11:52:00 | 显示全部楼层

Re:大家新年好,有个模板的问题想请教

继续
int redoint(){
        printf("redo int\n");
        return 0;
}
float redofloat(){
        printf("redo float\n");
        return 0;
}

int undo(){
        printf("undo\n");
        return 0;
}
void main(){
        typedef NormalFnNon<int> intfunc;
        typedef NormalFnNon<float> floatfunc;
        intfunc r1(&redoint);
        floatfunc r2(&redofloat);

        r1.Run();
        r2.Run();
        std::stack<intfunc> s;
        s.push(r1);
        //s.push(r2);
        s.top().Run();
        s.pop();
        //RUdo<int>  list;
}
压进堆栈的时候,不同类型的返回就不能进栈,拿基类当指针也没用,这个基类实际上不起作用,
lz应该考虑使用宏吧。
要是java这个问题贼好办。

0

主题

114

帖子

114

积分

注册会员

Rank: 2

积分
114
发表于 2007-2-24 22:00:00 | 显示全部楼层

Re:大家新年好,有个模板的问题想请教

返回类型不能启发编译器作特化的,因为C++允许写一个函数,返回值不做任何操作,编译器这个时候怎么知道你用的哪一个版本?

18

主题

573

帖子

573

积分

高级会员

Rank: 4

积分
573
发表于 2007-2-24 23:26:00 | 显示全部楼层

Re:大家新年好,有个模板的问题想请教

用设计模式的command模式不是就能实现redo和undo了吗?

15

主题

129

帖子

129

积分

注册会员

Rank: 2

积分
129
QQ
 楼主| 发表于 2007-2-25 13:15:00 | 显示全部楼层

Re:大家新年好,有个模板的问题想请教

这是目前改动后的结果,虽然解决了一般问题,可离我的目标还有一步.就是没法子使用返回类型了,虽然目前的确是用不上.
//-----------------------------------------------------------------------------------------
//基类
//-----------------------------------------------------------------------------------------
class FnCall
{
public:
        virtual void Run() = 0;
};
//-----------------------------------------------------------------------------------------
//无参的函数指针
//-----------------------------------------------------------------------------------------
template<class R>
class NormalFnNon:public FnCall
{
public:
        explicit NormalFnNon( R (*p)() ):fp(p){}
        void Run() {(*fp)();}
private:
        R (*fp)();
};
template<class R>
NormalFnNon<R>* CreateNFNon( R (*p)() )
{
        return new NormalFnNon<R>(p);
}
//-----------------------------------------------------------------------------------------
//一个参数的函数指针
//-----------------------------------------------------------------------------------------
template<class R,class A>
class NormalFnOne:public FnCall               
{
public:
        explicit NormalFnOne( R (*p)(A),const A& a )
                :_fp(p),_a(a){}
        void Run() {(*_fp)(_a);}
private:
        R (*_fp)(A);
        A _a;
};
template<class R,class A>
NormalFnOne<R,A>* CreateNFOne( R (*p)(A),const A& a )
{
        return new NormalFnOne<R,A>(p,a);
}
//-----------------------------------------------------------------------------------------
//实现
//-----------------------------------------------------------------------------------------
class RUdo
{
public:
        bool CanUndo()
        {
                return !_fn_undo.empty();
        }
        bool CanRedo()
        {
                return !_fn_redo.empty();
        }
        bool Redo()
        {
                if( _fn_redo.empty()==true ) return false;
                _fn_redo.top()._old_call->Run();
                _fn_undo.push(_fn_redo.top());
                _fn_redo.pop();
                return true;
        }
        bool Undo()
        {
                if( _fn_undo.empty()==true ) return false;
                _fn_undo.top()._opp_call->Run();
                _fn_redo.push(_fn_undo.top());
                _fn_undo.pop();
                return true;
        }
        template<class R>
        void Push( R(*f)() )
        {       
                clear_temp();
                add_operator( CreateNFNon(f) );
        }
        template<class R,class A>
        void Push( R(*f)(A),const A& a )
        {       
                clear_temp();
                add_operator( CreateNFOne(f,a) );
        }
private:
        void clear_temp()
        {
                while(_fn_redo.empty()==false)
                {
                        _fn_redo.pop();
                }
        }
void add_operator(FnCall* call)
        {
                if(_fn_undo.empty()==true || _fn_undo.top()._opp_call!=0 )
                {
                        Mutex mutex;
                        mutex._old_call = call;
                        _fn_undo.push(mutex);
                }
                else
                {
                        _fn_undo.top()._opp_call = call;
                }
        }
        struct Mutex                                //相反的操作
        {
                Mutex():_old_call(0),_opp_call(0){}
                FnCall*                _old_call;
                FnCall*                _opp_call;
        };
        std::stack<Mutex>        _fn_undo;        //函数调用
        std::stack<Mutex>        _fn_redo;        //临时的函数调用
};

15

主题

129

帖子

129

积分

注册会员

Rank: 2

积分
129
QQ
 楼主| 发表于 2007-2-25 13:19:00 | 显示全部楼层

Re: Re:大家新年好,有个模板的问题想请教

Johnson3D: Re:大家新年好,有个模板的问题想请教

返回类型不能启发编译器作特化的,因为C++允许写一个函数,返回值不做任何操作,编译器这个时候怎么知道你用的哪一个版本?

新的是可以用了,其实就是因为返回类型不需要才成功的.可我老是想着怎么把那个返回类型留下来,以备不测

15

主题

129

帖子

129

积分

注册会员

Rank: 2

积分
129
QQ
 楼主| 发表于 2007-2-25 13:19:00 | 显示全部楼层

Re: Re:大家新年好,有个模板的问题想请教

william9527: Re:大家新年好,有个模板的问题想请教

用设计模式的command模式不是就能实现redo和undo了吗?

谢了,等我这个demo做完了后一定好好看看设计模式.

15

主题

129

帖子

129

积分

注册会员

Rank: 2

积分
129
QQ
 楼主| 发表于 2007-2-25 20:50:00 | 显示全部楼层

Re:大家新年好,有个模板的问题想请教

//这是使用的方式
//说明:write和clear是相反的一对操作
//因为是使用的是自己写的库,库的接口全部采用类似write和clear的操作,使用的人无法接触到内部
//,因而调用的函数也相对简单
#include "ReUn.h"
#include <string>
#include <vector>
#include <iostream>
using namespace std;

vector<int> data(10);
void write(int index,int value)
{
        if(index>0 && index<data.size()) data[index] = value;
}
void clear(int index)
{
        if(index>0 && index<data.size()) data[index] = 0;
}
void print()
{
        for(int i=0;i<data.size();i++)
        {
                cout<<data<<" ";
        }
        cout<<endl;
}
typedef void (*FNOne)(int);
typedef void (*FNTwo)(int,int);
int main()
{
        int value = 0;
        RUdo rndo;
        write(5,15);
        print();
        rndo.StartAddOperator();        //定义一组操作的开始
        FNTwo old = write;
        FNOne opp = clear;
        rndo.Push(old,5,15);
        rndo.Push(opp,5);
        rndo.EndAddOperator();                //定义一组操作的结尾
        while(true)
        {
                cout<<"输入redo或undo:"<<endl;
                string s;
                cin>>s;
                if(s=="redo")
                        rndo.Redo();
                if(s=="undo")
                        rndo.Undo();
                print();
        }
}
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-26 11:54

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表