Reputation: 41
I understand how lambda functions work. The problem is that the program calls the function recursiveFunction() before the compiler has deduced what 'auto' should be. The thing is, it's a recursive function so the function itself is in the definition.
#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;
}
I've also implemented this using a class using templates in case that factors into the problem.
Here's the error message:
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);
Thanks!
Upvotes: 4
Views: 252
Reputation: 218323
If you want to avoid std::function
, you might do (requires C++14 for generic lambda):
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);
}
Upvotes: 0
Reputation: 10824
Couple possible answers:
So you could just do without the problematic auto
and associated deduction, and promise to know the type in advance.
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);
}
namespace {
int recursiveFunction(int) {
if (n <= 1) return 1;
else return n*recursiveFunction(n-1);
}
}
int Class<T>::foo(int x) {
return recursiveFunction(x);
}
#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;
}
Upvotes: 0
Reputation: 16248
Answered here:
The second snippet runs into [dcl.spec.auto]/10:
If the type of an entity with an undeduced placeholder type is needed to determine the type of an expression, the program is ill-formed.
The type of foo is needed to determine the type of the expression foo within the lambda body, but at that point you haven't deduced foo's type yet, so the program is ill-formed.
Further references:
Fix: 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;
}
Upvotes: 4