您如何在C ++函数中实现递归函数?

时间:2019-10-02 01:32:21

标签: c++ recursion lambda

我了解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);

谢谢!

3 个答案:

答案 0 :(得分:4)

已回答here

  

第二个片段进入[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;
}

答案 1 :(得分:0)

结合可能的答案:

  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;
}

答案 2 :(得分:0)

如果您想避免使用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