【问题标题】:Does C++11 does optimise away tail recursive calls in lambdas?C++11 是否优化了 lambda 中的尾递归调用?
【发布时间】:2012-10-28 23:05:37
【问题描述】:

我的暂定答案是否定的,如下测试代码所示:

#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 ()

有没有办法强制编译器优化 lambdas 中的递归尾调用?

提前感谢您的帮助。

编辑

我只是想澄清一下,我的意思是问 C++11 是否优化了 lambdas 中的递归尾调用。我使用的是 Visual Studio 2012,但如果绝对知道 GCC 进行了所需的优化,我可以切换环境。

【问题讨论】:

  • 你用的是什么编译器; stackoverflow.com/questions/5231823/…似乎表明vs2010可以做一些尾调用,还是你特指lambdas
  • 据我所知,该语言对此一无所知。如果您询问特定编译器是否执行此优化,您应该告诉我们您使用的是什么编译器(并且可能重新表述问题)。
  • 我正在使用 Visual Studio 2012。是的,正如问题所表明的那样,似乎正在优化实际函数,但不是 lambdas。我想知道是否有一个编译器开关可以用来强制编译器优化 lambdas。
  • 抱歉,我错过了 using namespace std; 指令。我也错过了前向声明。感谢您指出错误。

标签: c++ lambda c++11 tail-call-optimization


【解决方案1】:

您实际上并没有在“lambda”代码中进行尾调用,至少不是直接调用。 std::function 是一个多态函数包装器,这意味着它可以存储任何类型的可调用实体。 C++ 中的 lambda 具有唯一的、未命名的类类型,并且不是 std::function 对象,它们可以存储在其中。

由于std::function 使用类型擦除,它必须跳过几圈才能调用最初传递给它的东西。这些箍通常由虚函数或指向函数模板特化的函数指针和void* 完成。

间接的唯一性质使得优化器非常很难看穿它们。同样,编译器很难看穿std::function 并决定您是否有尾递归调用。

另一个问题是r 可能会在r 内更改或同时更改,因为它是一个简单的变量,突然间你不再有递归调用了!使用函数标识符,这是不可能的,它们不能在中途改变含义。

我只是想澄清一下,我的意思是问 C++11 是否优化了 lambdas 中的递归尾调用。

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

【讨论】:

  • 由此可知,如果要进行递归调用,lambda 表达式可能不是最好的工具。
  • 要牢记的重要警告。我不记得在C# 中遇到Func&lt;&gt; 的此类问题,所以我可能没有在C++ 中寻找问题。我应该检查我的代码。
猜你喜欢
  • 2013-08-04
  • 2012-11-15
  • 2011-09-04
  • 1970-01-01
  • 1970-01-01
  • 2017-04-18
  • 2021-05-30
  • 1970-01-01
  • 2014-07-24
相关资源
最近更新 更多