Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++11 如何使这个函数尾部递归?_C++11_Recursion_Tail Recursion - Fatal编程技术网

C++11 如何使这个函数尾部递归?

C++11 如何使这个函数尾部递归?,c++11,recursion,tail-recursion,C++11,Recursion,Tail Recursion,我试图使这个函数尾部递归,这样我就可以使用它来处理大量事件,而不会导致堆栈溢出。我确保将递归调用放在函数的最后一行,但它仍然用递归调用淹没调用堆栈 我还需要做些什么才能使它成为尾部递归的,还是我的编译器不知道如何优化它 我应该放弃这个函数而使用循环吗 template <class Csi> void GetEvents(EventHandle handle, vector<int> desiredCodes, vector<EventHandle> &

我试图使这个函数尾部递归,这样我就可以使用它来处理大量事件,而不会导致堆栈溢出。我确保将递归调用放在函数的最后一行,但它仍然用递归调用淹没调用堆栈

我还需要做些什么才能使它成为尾部递归的,还是我的编译器不知道如何优化它

我应该放弃这个函数而使用循环吗

template <class Csi>
void GetEvents(EventHandle handle, vector<int> desiredCodes, vector<EventHandle> &events, Csi &csi)
{
    if (handle == INVALID_HANDLE)
    {
        return;
    }

    int code = csi.GetEventCode(handle);
    bool codeSatisfiesSearch = (find(desiredCodes.begin(), desiredCodes.end(), code) != desiredCodes.end());
    if (codeSatisfiesSearch)
    {
        events.push_back(handle);

        handle = csi.FindNextEventEx(handle, &desiredCodes[0], 0, desiredCodes.size());
    }
    else
    {
        handle = csi.FindNextEventEx(handle, &desiredCodes[0], 0, desiredCodes.size());
    }
    return GetEvents(handle, desiredCodes, events, csi);
}
模板
void GetEvents(EventHandle句柄、vector desiredCodes、vector&events、Csi&Csi)
{
if(句柄==无效的\u句柄)
{
返回;
}
int code=csi.GetEventCode(句柄);
bool codeSatisfiesSearch=(查找(desiredCodes.begin(),desiredCodes.end(),code)!=desiredCodes.end());
if(代码满足性搜索)
{
事件。推回(手柄);
handle=csi.FindNextEventEx(handle,&desiredCodes[0],0,desiredCodes.size());
}
其他的
{
handle=csi.FindNextEventEx(handle,&desiredCodes[0],0,desiredCodes.size());
}
返回GetEvents(句柄、所需代码、事件、csi);
}

从表面上回答这个问题

在当前形式中,代码不适用于TCO,因为
vector desiredCodes
是按值传递的。它要求调用方在递归调用后销毁局部向量,所以尾部调用优化不是一个选项

当我更改代码以通过常量引用传递向量时,我注意到最新版本的
clang
确实优化了尾部调用:

但是,
gcc
仍然没有:。我注意到正是
push_back
阻止了gcc的优化——当注释掉时,递归调用被消除

在替换
事件时,我能够让gcc 9.2优化递归调用

events.resize(events.size() + 1);
events[events.size()  - 1] = handle;
所有这些都表明,C++中的TCO不是依赖的,因为它非常脆弱,依赖于不可预知的因素。这是一个不错的奖金,你可能会偶尔得到,但不是你可以建立你的设计


如果您对TCO感兴趣(例如,正如我所感兴趣的那样),您将更幸运地使用更可预测的语言,如C,或者更好地使用函数式bunch。

如果您使用编译器标志打开它,现代编译器可以执行此优化。为了获得它,我将您的代码修改为以下内容

在没有优化标志的情况下,第1724行执行递归非尾部调用

call GetEvents(EventHandle, std::vector<int, std::allocator<int> > const&, std::vector<EventHandle, std::allocator<EventHandle> >&, Csi&) #44.12
调用GetEvents(EventHandle,std::vector const&,std::vector&,Csi&)44.12
据我所知,尾部递归是可选的优化。这看起来像是一个使用递归实现的主循环,如果不应用优化,递归将严重破坏堆栈。因此,如果是这种情况,不要尝试使用递归来实现,而是自己手工编写循环。否则,其他人可能会尝试在不执行尾部递归的平台上编译您的代码,这对他们不起作用。这假设您可以首先触发优化。尝试通过常量引用传递
desiredCodes
。为什么不使用循环呢?您应该能够将逻辑封装在一个循环中,如
while(handle!=INVALID_handle){int code=csi.GetEventCode(handle);…}
为什么要使用尾部递归而不是(更明显的)循环?这是一个关于优化的问题。确定您使用的编译器、版本以及使用的构建标志非常重要。答案可能因构建配置的不同而大不相同。请参阅本文中的讨论。感谢您提供详细的答案。我对递归非常感兴趣,我想看看是否可以用它来解决这个问题,但我开始看到它的局限性和缺点。我将使用循环。
jmp GetEvents(EventHandle, std::vector<int, std::allocator<int> > const&, std::vector<EventHandle, std::allocator<EventHandle> >&, Csi&) #44.12
call GetEvents(EventHandle, std::vector<int, std::allocator<int> > const&, std::vector<EventHandle, std::allocator<EventHandle> >&, Csi&) #44.12