3

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

对于 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++ 相关的自动机)

为了澄清我的观点:

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

4

3 回答 3

3

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

除此之外,对某些类型的状态机进行编码的一种非常优雅的方法是将它们定义为 couroutine:
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)为每个协程分配一个单独的堆栈和寄存器空间。
这实质上使协程成为一个成熟的执行线程,唯一的区别是用户对线程调度负有全部责任(也称为协作多任务)。
boost 提供了一个可移植的实现:http:
//www.boost.org/doc/libs/1_54_0/libs/coroutine/doc/html/coroutine/intro.html

于 2013-07-08T14:52:52.260 回答
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 )以更一般地处理此模式。

但是,基本思想是每个状态都是一些常见“状态”类的子类,您可以使用多态性来确定每个状态所代表的不同动作和行为。指向通用“状态”基类的指针会跟踪您当前所处的状态。

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

于 2013-07-06T19:16:37.167 回答
1

您可以在 int 上使用模板值特化来实现您想要的。

(对不起,我在我的平板电脑上,所以我不能提供一个例子,我会在周日更新)

于 2013-07-06T21:00:16.263 回答