我意外地编写了一个编译时可执行状态机

2020-05-03 22:40:21

是的,你读对了那个标题。在研究创建有限状态机(FSM)的新方法时,我无意中设计了一个可以在编译时执行的状态机。有树枝之类的东西。今天,请允许我把你拉进我的兔子洞。有客人在下面总是更好。

我有一个朋友,你看,他在c++音响行业工作。DSP之类的好东西。每次我向他展示我觉得有趣的一段新代码时,他都会喋喋不休地说他的“音频回调”、“硬实时”和“跳过一帧”以及“和”。我告诉你,这是永无止境的。在与他正在从事的一个项目讨论他目前的一些问题时,我推荐了FSM。这将解决他的所有问题,并可能根除他的许多州管理缺陷。

状态机很棒。我爱他们,你也应该爱他们。当你必须要有状态的时候,它们就是你要走的路。不过,请记住我亲爱的朋友一直在胡言乱语的“音频回调”。嗯,在其中之一中,您不能使用std::function。显然,您甚至不能使用C函数指针。您确实希望您的编译器能够内联它认为合适的所有内容。

因此,我开始制作一个可内联的状态机。一个没有std::函数或函数指针的。反正我也想要一个。[剧透提醒]FSM还没有完成,我已经有点偏离了我的目标。

随着我新的FSM设计的发展,我一直在心不在焉地盯着我的理智逃脱,我意识到我做了什么。一个constexpr可执行状态机,具有许多您所期望的花哨功能。原谅我,比昂,因为我犯了罪。

由于稍后我将深入介绍c++的内容,不如从一个简单的演示开始。这是一个很有理论意义的例子,用来演示系统的功能。

如果我自己这么说的话,这个API,至少在Windows上是不错的。我本打算为微软的编译器写一首诗,但我的诗歌技巧却抛出了一个例外。相反,这里是一封致Visual Studio编译器的发自内心的信。当然,是在编译时编写的。

让我们来看看用来生成这部精彩而令人愉悦的文学杰作的代码。我假设你以前使用过FSM,因为在这里解释这个概念会把这篇已经太长的帖子变成一本太短的小说。我还将使用Visual Studio版本的代码,因为它更具可读性,并且不需要任何宏(Clang和GCC需要1个宏,稍后将详细介绍)。

//用于演示分支。#IF DEFINED(NDEBUG)STATIC CONSTEXPR bool DEBUG_BUILD=FALSE;#ELSE STATIC STATIC CONTEXR bool DEBUG_BUILD=TRUE;#endif//用于打开/关闭消息。静态常量表达式bool assert_val=TRUE;枚举类转换{do_intero,do_debug,do_release,do_paragage,do_outro,count,//count是FSM必需的};枚举类状态{info,debug,Release,Parage,Outtro,count,//count是FSM必需的};

这里没什么特别的。我们有几个编译时变量可供分支,并且我们定义了写信状态机。我们将从介绍开始,然后过渡到调试或发布,然后是段落,最后是Otro。

fsm_builder<;Transition,state>;builder;//INTO AUTO INTERO_TRANSFERIONS=builder.make_Transition<;Transition::do_debug,state::debug>;().make_Transition<;Transition::do_release,state::release>;();auto INTRO_EVENTS=builder.make_event<;FSM_EVENT::ON_ENTER>;([](AUTO&亲爱的";);如果常量表达式(DEBUG_BUILD){返回计算机。模板触发器<;转换::do_debug>;();}否则{返回.。

好的!。事情变得越来越有趣了。首先,我们创建一个fsm_builder。它需要了解我们的转换和州枚举类。我以前在这里讨论过这种非类型模板技术。我真喜欢它。它非常健壮,所有用户需要做的就是确保他的枚举以Count结束,这无论如何都是最佳实践。

使用该构建器,我们可以创建我们的过渡和事件。API是以这种“链接”风格编写的,以简化使用。Make_Transition接受转换枚举值和状态枚举值。这是哪个转换转到哪个状态之间的关联。调用不是由状态处理的转换将STATIC_ASSERT。

这些事件不言而喻。FSM支持标准ON_ENTER、ON_UPDATE、ON_EXIT和ON_ENTER_FROM。以及罕见的,但却是无限强大的,On_Exit_To。您必须为机器提供lambdas,因为函数指针是运行时的。每个事件lambdas的第一个参数是对状态机本身的引用。这对于运行时计算机非常有用,正如您将看到的,对于constexprMachines也是如此。在那之后,你可以添加任何你想要的论点,因为.。

然后,根据我们是否在DEBUG中编译,我们将触发do_debug树