0

I am trying to use recursive lambda functions with auto keyword as below.

#include <iostream>

using namespace std;

int main()
{
    auto func = []()->void{
        static int x = 0;
        cout << x << endl;
        if (x < 5) {
            func();
            x++;
        }
    };

    func();
    return 0;
}

But it is throwing compiler error as below.

main.cpp: In lambda function:
main.cpp:19:13: error: use of ‘func’ before deduction of ‘auto’
             func();
             ^~~~

I understood that we can achieve the same with std::function. But I wanted to know why I am getting error by using 'auto'.

I went through below stack overflow questions.

But I couldn't figure out why auto with lambda is throwing error in this case. Can anyone please let me know why I am getting this error?

kadina
  • 5,042
  • 4
  • 42
  • 83
  • Isn't the error message clear? `auto` is determined until the right-hand-side of the initialization is processed. – Jasper Kent Apr 05 '20 at 09:10
  • @JasperKent: I understood that by the error message. But I am already using 'void' as a return type explicitly. Then why compiler is not able to determine what is auto here. – kadina Apr 05 '20 at 09:13
  • BTW: What sense makes a lambda which did not capture anything if it defined and passed to a var. In this case every "normal" function fits much better. What I see in this example is a abuse of a lambda. A lambda is very nice as ad hoc function object parameter to a given algorithm. But abuse it as a normal function makes code only less readable. My opinion :-) – Klaus Apr 05 '20 at 09:13
  • @kadinaAs I say, because is has to evaluate the entire of the right-hand-side – Jasper Kent Apr 05 '20 at 09:14
  • @Klaus: I know it doesn't make much sense in this case :) I just wanted to understand why this is not working. So didn't use capture and wrote a simple one. – kadina Apr 05 '20 at 09:15
  • @Klaus in fp languages it's obviously abuse, howver in c++ it may be the only approch to generate runtime functions to clean up meaningless functions in *namespace block*, i deem :/ Although "recursive lambdas" are always seemed to be strange keeping lambda calculus in mind – con ko Apr 05 '20 at 09:55
  • @JohnDing: "only approch to generate runtime functions to clean up meaningless functions in namespace block". What is a runtime function? I do not understand a "requirement" to have less functions in block scope. And BTW: You can have functions local to a module by making them static. As said: Abuse! :-) For having it as an academic example to get a minimal example, it is absolutely ok, but never in productive code. – Klaus Apr 06 '20 at 07:07

2 Answers2

1

The problem is not the return-type of the lambda expression. The problem is the type of the lambda itself.

Each lambda expression is a unique anonymous type.

In your code, the compiler knows that the lambda returns void, but it doesn't yet know the type of the lambda, since it has not fully parsed it yet.

To give a counter example to highlight the issue.

#include <iostream>

int main()
{
    int x;
    auto func = [&](){
        // func is going to become an int here, but the compiler does not know that yet
        // it has to parse the whole expression first.
        x = func;
        return 5;
    }(); // <-- calling the lambda and assigning the return value to func
}
super
  • 12,335
  • 2
  • 19
  • 29
0

You cannot make lambda recursive. Lambdas cannot be recursive because they don't have a name. See this: https://en.cppreference.com/w/cpp/language/lambda

an unnamed function object capable of capturing variables in scope.

Here lambda generate before initialization, thus the compiler gives you an error.

The only way to implement it in real lambda calculus is to use Y combinator. But I think that's meaningless in C++. Especially here you are not using enclosure at all.

In C++, there's another way to implement it: use std::function to replace auto, and then call the std::function rather than lambda instead.

con ko
  • 1,368
  • 5
  • 18