C++11是否会优化lambda中的尾递归调用?

3

我的初步答案是否定的,根据以下测试代码观察:

#include <functional>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

void TestFunc (void);
int TestFuncHelper (vector<int>&, int, int);

int main (int argc, char* argv[]) {
    TestFunc ();
    return 0;
} // End main ()

void TestFunc (void) {
    // Recursive lambda
    function<int (vector<int>&, int, int)> r = [&] (vector<int>& v_, int d_, int a_) {
        if (d_ == v_.size ()) return a_;
        else return r (v_, d_ + 1, a_ + v_.at (d_));
    };
    int UpperLimit = 100000; // Change this value to possibly observe different behaviour
    vector<int> v;
    for (auto i = 1; i <= UpperLimit; i++) v.push_back (i);
    // cout << TestFuncHelper (v, 0, 0) << endl; // Uncomment this, and the programme works
    // cout << r (v, 0, 0) << endl; // Uncomment this, and we have this web site
} // End Test ()

int TestFuncHelper (vector<int>& v_, int d_, int a_) {
    if (d_ == v_.size ()) return a_;
        else return TestFuncHelper (v_, d_ + 1, a_ + v_.at (d_));
} // End TestHelper ()

有没有一种方法可以强制编译器优化lambda中的递归尾调用?感谢您的帮助。
编辑:我只是想澄清,我是想问C++11是否会优化lambda中的递归尾调用。我正在使用Visual Studio 2012,但如果GCC绝对执行所需的优化,则可以切换环境。

你使用的编译器是什么?https://dev59.com/7m435IYBdhLWcg3wvy6_?rq=1 似乎表明vs2010可以进行一些尾调用,或者你特别指的是lambda函数。 - Foon
2
据我所知,这种语言并没有涉及到这个问题。如果你想询问一个特定编译器是否执行这种优化,你应该告诉我们你使用的是哪个编译器(并可能需要重新表达问题)。 - Keith Thompson
我在使用Visual Studio 2012。是的,正如问题所指出的那样,似乎实际函数正在被优化,但不包括lambda表达式。我想知道是否有编译器开关可以强制编译器优化lambda表达式。 - Shredderroy
抱歉,我漏掉了 using namespace std; 指令。我还漏掉了前向声明。感谢指出这些错误。 - Shredderroy
1个回答

9
您在“lambda”代码中实际上并没有进行尾调用,至少不是直接的。 std :: function 是一个多态函数包装器,这意味着它可以存储任何类型的可调用实体。C ++中的lambda具有唯一的未命名类类型,并且不是 std :: function 对象,它们只能存储在其中。
由于 std :: function 使用类型擦除,因此必须通过几个步骤来调用最初传递给它的内容。这些步骤通常使用虚函数或指向函数模板特化和 void * 的函数指针来完成。
间接性的本质使得优化器非常难以穿透它们。同样地,编译器很难看穿 std :: function 并决定您是否有尾递归调用。
另一个问题是, r 可能会从 r 内部或同时更改,因为它是一个简单的变量,突然之间您就没有递归调用了!对于函数标识符,这是不可能的,它们不能在中途更改含义。

我只是想澄清我想问的是C ++ 11是否优化lambda中的递归尾调用。

C ++ 11标准描述了抽象机器上的工作程序的行为,而不是编译器如何优化程序。实际上,只有在不改变程序的可观察行为时(使用复制省略/(N)RVO为例)才允许编译器优化事物。

2
由此可见,如果您想进行递归调用,则 lambda 表达式可能不是最佳工具。 - Luc Danton
记住一个重要的告诫。我不记得在C#中使用Func<>时遇到过这样的问题,所以我可能没有在C++中留意这个问题。我应该检查一下我的代码。 - Shredderroy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接