将无状态 C++ 函数从里到外转换为有状态函数

Turning a stateless C++ function inside out, into a stateful one

我有一个 C++ 字符解析函数,它是在它自己的线程中写入 运行 的。它旨在每次需要处理更多数据时进行阻塞调用,并且在处理完所有数据之前永远不会 return 。像这样:

void runParser() {
    while(true /*returns only when EOF encountered*/) {
        //...
        c = getNext();  //blocking call
        //...
             //...
             c = getNext();  //blocking call
             //...
        //...
        c = getNext();  //blocking call
        //...
            //...
                //...
                    c = getNext();  //blocking call
                    //...
                //...
                c = getNext();  //blocking call
            //...
        //...50 more lines of code...
    }
}

该函数在这种阻塞输入调用的实例中乱七八糟,在多种不同的情况下会有不同的解释。

我需要彻底改变功能。我不需要一个等待输入的单一函数,而是需要一个可以同步调用的函数,以便在新数据可用时处理每一位新数据。这意味着解析器代码需要从无状态转变为记住其状态。我需要尽快以最小的努力修改代码。

我初步的想法是修改函数如下:

  1. 用静态变量替换局部变量(因此函数保持状态)

  2. 用 return 语句替换阻塞调用,前面是 'current code position' 变量的赋值。

  3. 当新输入可用时,使用新数据再次调用函数。

  4. 函数的开头使用一个switch()和一堆goto跳回到它之前的位置。

任何人都可以提出一个更优雅、更简洁并且可能不涉及 goto 的替代方案吗?例如,C++ 是否还有其他任何可用于实现这些类型的 'stateful returns'?

要创建有状态函数,请使用仿函数。这是具有重载 () 运算符的 class 的对象。您在构造函数设置的初始状态下实例化此对象,并在调用 theObject () 期间调整状态,如前所述,该状态保存在对象内部。

不要使用static:这些几乎是变相的全局变量。

有一项涉及 await 关键字的 Microsoft 提案可以使您的更改变得微不足道。但这还没有。

该提案到当前 C++ 代码的 "mechanical" 转换看起来像您的解决方案,除了我们制作 class 成员状态变量而不是静态状态变量和 operator()。他们也支持组合,但你不需要那个。

您可以通过将标签直接存储在 void pointer 指针和 goto 中来代替开关维护。

可以从 goto 解决方案进行重构。获取 returns 之间的每个 运行 代码,首先将其放入 lambda,然后放入方法。这可能很困难、不可能或毫无意义,但重构最终可能会取代 goto。您最终可能会得到一个状态机,可以说它比 spagetti goto 更容易理解。

真正干净的解决方案正在等待某些未来版本的 C++ 中的协程;对不起。您或许可以通过研究当今人们如何实现协程来获得灵感...