0

I was trying to use lambda function recursively as below.

#include <iostream>
#include <functional>

using namespace std;

int main()
{
    std::function<int(int)> x = [](int y) -> int {
        if(y == 0) {
            return 0;
        } else {
            return y + x(--y);
        }
    };
    
    cout << x(3) << endl;
}

But it is throwing below errors.

main.cpp: In lambda function:
main.cpp:20:24: error: ‘x’ is not captured
             return y + x(--y);
                        ^
main.cpp:16:34: note: the lambda has no capture-default
     std::function<int(int)> x = [](int y) -> int {
                                  ^
main.cpp:16:29: note: ‘std::function x’ declared here
     std::function<int(int)> x = [](int y) -> int {
                             ^

Is this throwing error because x is not fully defined when compiler reaches x(--y)? Can any one please let me know how to fix this issue.

kadina
  • 4,024
  • 3
  • 26
  • 60
  • 1
    Did you try capturing `x` as the error messages say? `[&x](int y) -> int { /* ... */ }` – L. F. Feb 15 '21 at 01:42
  • I would rather use a normal function for that. You are trying to capture something that is not declared already. Which is the lambda function it self. – Bybit360 Feb 15 '21 at 01:43
  • See the "capturing variables" section of this answer https://stackoverflow.com/a/7627218/9716597 – L. F. Feb 15 '21 at 01:43
  • When I tried to capture as &x, it is giving the output as '3'. But it should give output as 6 (3 + 2 + 1). – kadina Feb 15 '21 at 01:44
  • 1
    @kadina Change `x(--y)` to `x(y-1)` to avoid unsequenced point issue. – songyuanyao Feb 15 '21 at 01:57
  • @songyuanyao: Thanks a lot. It is working fine. Can you please post this as answer. I will accept it. – kadina Feb 15 '21 at 01:59
  • *"Is this throwing error because x is not fully defined when [...]"* -- why would you come to this conclusion when the error message rather clearly identifies something else ("not captured") as the reason for the error? – JaMiT Feb 15 '21 at 02:19
  • Notice that your `std::function` is not really copyable afterward. One way to avoid that is "y-connector", `auto x = [](auto self, int y) -> int{ return y == 0 ? 0 : y + self(self, y - 1); }; std::cout << x(x, 3);` (as bonus, no-longer overhead with `std::function`). – Jarod42 Feb 15 '21 at 09:39

1 Answers1

3

Updated

This line looks suspcious:

return y + x(--y);

You're decrementing y and evaluating it within the same expression. The rules vary between "defined" and "undefined" on statements like this. But I suspect you really want this:

return y + x(y-1);

Split your declaration of x separate from the assignment. And capture x by reference:

int main()
{
    std::function<int(int)> x;
    x = [&x](int y) -> int {
        if (y == 0) {
            return 0;
        }
        else {
            return y + x(y-1);
        }
    };

    cout << x(3) << endl;
}

The result is that 6 will get printed.

selbie
  • 82,148
  • 13
  • 83
  • 154