从C++中的函数返回递归lambda

jca*_*er2 8 c++ lambda

请参阅以下代码:

std::function<int(int)> makeFibonacci() {
    std::function<int(int)> fibonacci = [&fibonacci](int n) {
        if (n == 1) {
            return 1;
        }
        if (n == 2) {
            return 1;
        }
        return fibonacci(n-1) + fibonacci(n-2);
    };
    return fibonacci;
};

int main() {
    std::function<int(int)> fibonacci = makeFibonacci();
    std::cout << fibonacci(6) << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我运行它时,数字8按预期输出.但是,当我将捕获更改&fibonacci为仅fibonacci用于副本捕获时,程序实际上会main在其运行的第一行上进行段错误makeFibonacci.

如果fibonacci(第2行)是makeFibonacci函数的局部函数,因此当函数退出时超出范围,如何通过引用捕获并递归使用?另外,为什么当我通过副本捕获lambda时程序会出现段错误?

Cur*_*ous 12

如果fibonacci(第2行)是makeFibonacci()函数的局部函数,因此当函数退出时超出范围,如何通过引用捕获并递归使用?

这是函数按预期工作的机会.你有什么是未定义的行为.您正在引用超出函数范围的对象.

另外,为什么当我通过副本捕获lambda时程序会出现段错误?

这是因为std::function初始化的原因.lambda首先std::function被初始化,然后用lambda初始化.这意味着您正在复制std::function未初始化的实例,因此它可能不处于允许良好副本的状态.不变量在内部被破坏,这可能导致分段错误.


您可以更高效地创建递归lambda函数,而无需std::function使用多态lambda,如下所示

auto makeFibonacci() {
    auto fib = [](int n, auto& self) {
        if (n == 1) {
            return 1;
        }
        if (n == 2) {
            return 1;
        }
        return self(n - 1, self) + self(n - 2, self);
    };
    return [fib](int n) {
        return fib(n, fib);
    };
};
Run Code Online (Sandbox Code Playgroud)

lambda 拥有它所需要的所有状态.然后你可以像这样使用它

auto fibonacci = makeFibonacci();
cout << fibonacci(6) << endl;
Run Code Online (Sandbox Code Playgroud)

另请注意,这可能是计算斐波纳契数的最差方法.

  • @Henri其实没有.lambda直接存储为函数对象,它不需要衰减到函数指针,这在lambda捕获时是不可能的. (2认同)