【问题标题】:How do you implement a recursive function in a function in C++?如何在 C++ 中的函数中实现递归函数?
【发布时间】:2019-10-02 01:32:21
【问题描述】:

我了解 lambda 函数的工作原理。问题是程序在编译器推断出“auto”应该是什么之前调用了函数 recursiveFunction()。问题是,它是一个递归函数,所以函数本身就在定义中。

#include <iostream>
using namespace std;

template <class T>
class Class {
    public:
        int foo(int x);
};

template <class T>
int Class<T>::foo(int x) {
    auto recursiveFunction = [=](int n)->int {
        if (n <= 1) return 1;
        else return n*recursiveFunction(n-1);
    };
    return recursiveFunction(x);
}

int main() {
    Class<int> c;
    cout << c.foo(5) << endl;
    return 0;
}

我还使用一个使用模板的类来实现这一点,以防问题出现。

这是错误信息:

main.cpp: In instantiation of 'int Class<T>::foo(int) [with T = int]':
main.cpp:21:20:   required from here
main.cpp:14:40: error: use of 'recursiveFunction' before deduction of 'auto'
         else return n*recursiveFunction(n-1);

谢谢!

【问题讨论】:

  • 我其实不明白为什么你需要使用auto而不是像function&lt;int(int)&gt;这样清楚地写类型签名。我的意思是,当我们创建一个递归函数时,我们通常需要知道返回值是什么,以便我们可以使用它并重新调用该函数,对吗?
  • 赞成,因为它带有一个最小的例子! (特别值得一提的是新贡献者。)
  • @WisnuAdiNurcahyo 是的 - 我也在想同样的事情。我不知道 function&lt;int(int)&gt; 存在...谢谢!
  • @SamWilliams 当然。祝你有美好的一天!

标签: c++ recursion lambda


【解决方案1】:

回复here:

第二个 sn-p 运行到 [dcl.spec.auto]/10:

如果需要使用具有未推导占位符类型的实体类型来确定表达式的类型,则程序格式错误。

需要 foo 的类型来确定 lambda 主体中表达式 foo 的类型,但此时您还没有推断出 foo 的类型,因此程序是非良构的。

更多参考资料:

修复:https://godbolt.org/z/np3ULe

#include <iostream>
#include <functional>

template <class T>
class Class {
 public:
  int foo(int x);
};

template <class T>
int Class<T>::foo(int x) {
  std::function<int(int)> fac = [&fac](int n) -> int {
    if (n <= 1)
      return 1;
    else
      return n * fac(n - 1);
  };
  return fac(x);
}

int main() {
  Class<int> c;
  std::cout << c.foo(5) << std::endl;
  return 0;
}

【讨论】:

  • 吹毛求疵:fib 应该是 fact 吗?
  • 是的,@LegendofPedro,我在你之前几秒钟就发现了这一点。不过很好找!
  • 假设 Class 有一个私有变量,例如 int p。如果我希望函数 fac 能够使用它,是否需要对 std::function&lt;int(int)&gt; fac = [&amp;fac](int n) -&gt; int 进行任何更改?
  • 您可以通过值或引用捕获int p。通过引用捕获fac 很重要。但是p 可以按值捕获(即,它被复制到函数中,并且如果类中的 p 发生更改,则不会更新。)。如果通过引用捕获,则 lambda 中使用的 p 和类中的 p 将始终相同。
  • 也许更具体:std::function&lt;int(int)&gt; fac = [&amp;fac, p](int n) -&gt; int
【解决方案2】:

几个可能的答案:

  1. 类型擦除;您实际上不需要知道 recursiveFunction 的类型,只需确定其签名即可。

所以你可以不使用有问题的auto 和相关的推论,并承诺提前知道类型。

template <class T>
int Class<T>::foo(int x) {
    std::function<int(int)> recursiveFunction;
    recursiveFunction = [=](int n)->int {
        if (n <= 1) return 1;
        else return n*recursiveFunction(n-1);
    };
    return recursiveFunction(x);
}
  1. 如果这不仅仅是一个过于简单的示例,那么您似乎实际上并没有捕获任何状态,因此您可以只使用正常的递归函数而不是 lambda。
namespace {
    int recursiveFunction(int) {
        if (n <= 1) return 1;
        else return n*recursiveFunction(n-1);    
    }
}

int Class<T>::foo(int x) {
    return recursiveFunction(x);
}
  1. 如果 lambda 方面确实很重要,那么您正在寻找“Y 组合器”。这在 C++ 中不是很简单,但类似于:
#include <iostream>
#include <functional>

template <class T>
class Class {
    public:
        int foo(int x);
};

template<class F>
struct function_traits;

template<class R, class T>
struct function_traits<R(T)> {
    typedef R return_type;
    typedef T arg_type;
};

// function pointer
template<class R, class... Args>
struct function_traits<R(*)(Args...)> : public function_traits<R(Args...)>{}};

template <typename Signature>
auto y (std::function<typename function_traits<Signature>::return_type(typename function_traits<Signature>::arg_type, std::function<Signature>)> f) 
    -> std::function<Signature>
{
    return [f](typename function_traits<Signature>::arg_type n) -> typename function_traits<Signature>::return_type { return f(n,y(f)); };
}

template <class T>
int Class<T>::foo(int x) {
   return y<int(int)>([=](int n, auto recursiveFunction) -> int {
        if (n <= 1) return 1;
        else return n*recursiveFunction(n-1);    
    })(5);
}

int main() {
    Class<int> c;
    std::cout << c.foo(5) << std::endl;
    return 0;
}

【讨论】:

  • Y-combinator 不需要来自 std::function 的类型擦除。
  • 不应该,但是没有它我不知道如何表达尾随返回类型(因为返回表达式提到了y,所以推导不起作用。
  • 类似的东西:Demo.
【解决方案3】:

如果你想避免std::function,你可以这样做(对于通用 lambda 需要 C++14):

int Class<T>::foo(int x) {
    auto recursiveFunction = [](auto recFunc, int n) -> int
    {
        if (n <= 1) return 1;
        else return n * recFunc(recFunc, n - 1);
    };
    return recursiveFunction(recursiveFunction, x);
}

Demo

【讨论】:

    猜你喜欢
    • 2016-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2013-04-21
    • 2020-08-27
    • 1970-01-01
    • 2017-11-26
    相关资源
    最近更新 更多