Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional operator inside C++ fibonacci lambda

While checking how to implement a recursive lambda function I stumbled upon this solution

#include <iostream>
using namespace std;

int main() {
    auto fr = [] (int n, auto&& fr) {
        if (n < 2)
            return n;
        else
            return fr(n-1,fr) + fr(n-2,fr);
    };
    auto fib = [&fr] (int n) {return fr(n,fr);};
    
    int n = 10;
    cout << "fib(" << n << ") = " << fib(n) << endl;
}

Which works great. However, trying a subtle change such as

auto fr = [] (int n, auto&& fr) {
        return n < 2 ? n : fr(n-1,fr) + fr(n-2,fr);
    };

Gives the following compilation error:

error: use of 'main()::<lambda(int, auto:1&&)> [with auto:1 = main()::<lambda(int, auto:1&&)>&]' before deduction of 'auto'

What I'm missing?

Also, I though of another way of making this code more compact, as having two lambdas seems a bit messy. It is possible to execute a lambda immediately after declaration by placing a parentheses after it, so would it be possible to do something like this?

auto fib = [] (int n) {
        auto fr = [] (int n, auto&& fr) {
            return n < 2 ? n : fr(n-1,fr) + fr(n-2,fr);
        }(n, fr);
    };

This way, when the function fib is called, the function fr is declared and called automatically. However, I'm new to lambdas and don't know if the syntax is even close to making sense...

Thanks in advance!

like image 823
Cnoob Avatar asked Mar 04 '26 22:03

Cnoob


1 Answers

This is a subtle chicken vs. egg problem.

[] (int n, auto&& fr) { ... }

Before this closure can be used its return type must be deduced.

 return n;

n is an int. This means that the closure's return type can be deduced as an int. The return statement serves to deduce the closure's return type.

return n < 2 ? n : fr(n-1,fr) + fr(n-2,fr);

The type of this ternary expression can only be determined by figuring out what integer promotion rules apply here, if any. One of the expressions is n, and int, and the other expression's type is ...what exactly? It's unknown. Fail.

The solution is is to explicitly define the closure's return type:

    auto fr = [] (int n, auto&& fr) -> int {
            return n < 2 ? n : fr(n-1,fr) + fr(n-2,fr);
    };
like image 156
Sam Varshavchik Avatar answered Mar 06 '26 10:03

Sam Varshavchik