有没有办法在不添加到调用堆栈的情况下调用函数?

Is there a way to call a function without adding to the call stack?

我有一些 goto 的 C++ 代码看起来像

#include <stdlib.h>
void test0()
{
    int i = 0;
loop:
    i++;
    if (i > 10) goto done;
    goto loop;
done:
    exit(EXIT_SUCCESS);
}

我想去掉 goto,同时(大部分)保留原始代码的外观;或多或少排除了 forwhile 等(除非它们隐藏在宏后面),因为这会过多地改变现有代码的外观。想象一下,想要最小化现有代码和更改代码之间的“差异”。

一个想法是使用 class 方法:

class test1 final
{
    int i = 0;
    void goto_loop()
    {
        i++;
        if (i > 10) goto_done();
        goto_loop();
    }
    void goto_done()
    {
        exit(EXIT_SUCCESS);
    }
public:
    test1() { goto_loop(); }
};

这有效,但每次调用 goto_loop() 都会添加到调用堆栈中。有什么方法可以进行类似 exec 的函数调用吗?也就是说,以某种方式“内联”调用函数...执行额外的代码 而不 添加到调用堆栈?有没有办法使尾递归显式化?

使用 C++20(甚至 C++23)是可以接受的,尽管 C++17 解决方案会“不错”。


致所有想知道“为什么?”的人真正的原码是BASIC ...

听起来你想要 ensure tail call optimization. At present there's no standard way to do this, but if you're using Clang you can use the clang::musttail 属性。

循环可能会保留代码结构:

void test2()
{
    int i = 0;
    for (;;) {
        i++;
        if (i > 10) break;
        continue;
    }
    exit(EXIT_SUCCESS);
}

即使

void test3()
{
    for (int i = 0; i < 11; ++i) {
        /*Empty*/
    }
    exit(EXIT_SUCCESS);
}

会更地道(假设一些有用的代码,因为循环实际上是无用的)。

我的解决方案是编写一个 exec() 停止递归的例程:

template<typename Func>
void exec(const Func& f)
{
    using function_t = Func;
    static std::map<const function_t*, size_t> functions;
    const auto it = functions.find(&f);
    if (it == functions.end())
    {
        functions[&f] = 1;
        while (functions[&f] > 0)
        {
            f();
            functions[&f]--;
        }
        functions.erase(&f);
    }
    else
    {
        functions[&f]++;
    }
}

使用该实用程序,我或多或少可以保留现有代码的外观

class test4 final
{
    int i = 0;
    void goto_loop_() {
        i++;
        if (i > 10) goto_done(); } 
    void goto_loop() { goto_loop_(); static const auto f = [&]() { goto_loop(); }; exec(f); }
    void goto_done()
    {
        exit(EXIT_SUCCESS);
    }
public:
    test4() { goto_loop(); }
};

(使用 lambda 避免了指向成员函数的指针的麻烦。)