如何在C ++中进行自动机/状态机编码?

时间:2013-07-06 18:21:03

标签: c++ c++11 state state-machine automata

我已经在另一种编程语言中使用它,它非常有用。

我无法为C ++找到任何相关内容。

让我们举个例子:

void change();

enum
{
    end = 0,
    gmx
}

int
    gExitType;

int main()
{
    gExitType = end;
    SetTimer(&change, 10000, 0);
    return 0;
}

void ApplicationExit()
{
    switch (gExitType)
    {
        case end:
            printf("This application was ended by the server");
        case gmx:
            printf("This application was ended by the timer");
    }
    ::exit(0);
}

void change()
{
    gExitType = gmx;
    ApplicationExit();
}

这就是我们在C ++中如何做到这一点,但是当使用状态机/自动机时,我可以用另一种语言做这样的事情:

void change();

int main()
{
    state exitType:end;
    SetTimer(&change, 10000, 0);
    return 0;
}

void ApplicationExit() <exitType:end>
{
    printf("This application was ended by the server");
}

void ApplicationExit() <exitType:gmx>
{
    printf("This application ended by the timer");
}

void change()
{
    state exitType:gmx;
    ApplicationExit();
}

在我的选择中,这是一种非常优雅的实现方式。 我将如何在C ++中执行此操作?这段代码似乎不起作用(显然我找不到任何与C ++相关的自动机)

澄清我的意见:

  

那么使用这种技术有什么好处?好吧,你可以清楚地看到代码更小;我添加了一个enum到第一个版本,使示例更相似,但ApplicationExit函数肯定更小。它也更明确 - 你不需要函数中的大型switch语句来确定发生了什么,如果你想要你可以将不同的ApplicationExits放在不同的文件中来独立处理不同的代码集。它还使用较少的全局变量。

3 个答案:

答案 0 :(得分:3)

像Boost.statechart这样的C ++库专门为编码状态机提供了丰富的支持:
http://www.boost.org/doc/libs/1_54_0/libs/statechart/doc/tutorial.html

除此之外,编码某些类型的状态机的一种非常优雅的方法是将它们定义为一个例程:
http://c2.com/cgi/wiki?CoRoutine
http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-to-state-machines/

C ++中不直接支持协同程序,但有两种可能的方法 实施它们:

1)使用类似于实现duff设备的技术,详细解释如下:
http://blog.think-async.com/search/label/coroutines
这与C#迭代器的工作方式非常相似,并且一个限制是,只能从协程调用堆栈中的最顶层函数完成协同处理。 OTOH,这种方法的优点是每个协程实例都需要很少的内存。

2)为每个协程分配一个单独的堆栈并注册空间。
这实际上使协程成为一个完整的执行线程,唯一的区别是用户对线程调度负有全部责任(也称为cooperative multi-tasking)。
可以通过boost获得便携式实施方案:
http://www.boost.org/doc/libs/1_54_0/libs/coroutine/doc/html/coroutine/intro.html

答案 1 :(得分:2)

对于此特定示例,您可以使用对象和多态来表示不同的状态。例如:

class StateObject
{
    public:
        virtual void action(void) = 0;
};

class EndedBy : public StateObject
{
    private:
        const char *const reason;

    public:
        EndedBy( const char *const reason_ ) : reason( reason_ ) { }
        virtual void action(void)
        {
            puts(reason);
        }
};

EndedBy EndedByServer("This application was ended by the server");
EndedBy EndedByTimer ("This application ended by the timer");

StateObject *state = &EndedByServer;

void change()
{
    state = &EndedByTimer;
}

void ApplicationExit()
{
    state->action();
    ::exit(0);
}

int main()
{
    SetTimer(&change, 10000, 0);

    // whatever stuff here... 
    // presumably eventually causes ApplicationExit() to get called before return 0;

    return 0;
}

那就是说,这不是很好的设计,而且一般意义上它不是FSM。但是,它会满足您的迫切需要。

您可以查找状态模式(一个参考:http://en.wikipedia.org/wiki/State_pattern)以获得对此模式的更一般处理。

但基本思想是每个状态都是某个常见“状态”类的子类,您可以使用多态来确定每个状态所代表的不同操作和行为。指向公共“状态”基类的指针然后跟踪您当前所处的状态。

状态对象可以是不同的类型,或者在上面的示例中,相同对象的不同实例配置不同,或者是混合。

答案 2 :(得分:1)

您可以对int使用模板值专门化来实现您想要的功能。

(抱歉,我在平板电脑上,所以我无法提供示例,我将在周日更新)