【发布时间】:2017-02-03 16:57:54
【问题描述】:
考虑一个普通的递归函数:
#include <iostream>
#include <functional>
void f(unsigned long long int x) {
std::cout << x << "\n";
if(x < 1e9)
f(x+1);
}
int main() {
f(1);
return 0;
}
这终止于 43033。
现在考虑一个递归 lambda:
#include <iostream>
#include <functional>
int main() {
std::function<void(int)> g = [&g](unsigned long long int x) {
std::cout << x << "\n";
if(x < 1e9)
g(x+1);
};
g(1);
return 0;
}
这会在 11736 的堆栈深度低得多时终止。
为什么 lambda 的最大堆栈深度较低?
(使用g++ (GCC) 5.4.0编译,使用-std=c++14 -Wall)
另请注意,使用-O3 优化进行编译允许几乎无限递归深度,但 lambda 仍终止于 25k。
编辑:在@Yakk 之后,这里是Y-combinator 的结果:
#include <iostream>
#include <functional>
using namespace std;
template <typename T, typename R>
function<R(T)> Y(function<function<R(T)>(function<R(T)>)> f) {
// Y f = f (λx.(Y f) x)
return f([=](T x) { return Y(f)(x); });
}
int main() {
using fg = function<void(int)>;
function<fg(fg)> sg = [](fg g) {
return [g](unsigned long long int x) {
std::cout << x << "\n";
if(x < 1e9)
g(x+1);
};
};
Y(sg)(1);
return 0;
}
这在 4781 和 9221 分别有和没有-O3 终止。
【问题讨论】:
-
@DieterLücking 详细说明?
-
尝试直接使用 lambda (
auto f) 我认为开销在std::function -
@Motti 它不会编译,因为它需要事先知道函数签名才能递归!
-
@prakharsingh95,好点,反正@Yakk 说开销在
std::function中,而不是在 lambda 中。 -
栈可以容纳 N 个字节。您可以在堆栈中放入 M 个小部件或 K 个小工具。小部件和小工具占用不同的字节数。又是什么问题?
标签: c++ function recursion lambda