Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call C++ recursive lambda in the same line where it is declared

This is mostly a one liner style type of question, I would normally write this code in multiple lines anyway for readability reasons.

So my question is can I call the recursive lambda in the same statement where it is defined?

So instead of this:

int n=3;
function<void(int)> f {[n,&f](int i){if (i>1) { cout << "func(a, "; f(i-1); cout << ")";} else cout << "a";}};
f(n);

call the function with n in the same line where f is defined.

like image 562
NoSenseEtAl Avatar asked Mar 14 '17 21:03

NoSenseEtAl


People also ask

How do you call a recursive lambda function?

The recipe is simple: If you want to call a lambda recursively, just add an auto&& parameter taking the function again and call that. This produces basically optimal assembly and can be used in combination with capturing.

Can lambda function be recursive C++?

But a lambda cannot be recursive, it has no way to invoke itself.

How do you declare lambda in C++?

Creating a Lambda Expression in C++auto greet = []() { // lambda function body }; Here, [] is called the lambda introducer which denotes the start of the lambda expression. () is called the parameter list which is similar to the () operator of a normal function.

Can a lambda function invoke itself?

This is an example of a function that will recursively call itself. Warning It's possible to run into infinite loops with recursive calls.


4 Answers

In one statement which declares several variables ;-)
Mostly not what you want:

std::function<void(int)>
    f {[&f](int i){
        if (i>1) {
            std::cout << "func(a, "; f(i-1); std::cout << ")";}
        else
            std::cout << "a";
    }},
    dummy((f(3), nullptr));

Demo

like image 153
Jarod42 Avatar answered Oct 31 '22 08:10

Jarod42


Let me offer a glimpse into the functional programming world, where people usually use combinators to deal with recursive lambdas. There was a proposal (P0200r0) last year to add a simple Y-combinator to the standard library.

Leaving aside the question whether it is a good idea to do this, this would allow you to write and invoke a recursive lambda like this:

y_combinator([](auto self, int i){
    if (i>1) {
        std::cout << "func(a, ";
        self(i-1);
        std::cout << ")";
    } else {
        std::cout << "a";
    }
})(6);

The basic idea here is that the y-combinator is a higher order function that wraps a lambda which is passed 'itself' as a first argument. The combinator takes care of wrapping the self argument away for all invocations of the lambda.

You can try it in coliru.

like image 39
ComicSansMS Avatar answered Oct 31 '22 07:10

ComicSansMS


As a matter of fact, you can. Here is a complete example which compiles and runs fine with g++ -std=c++11:

#include <iostream>
#include <functional>

int main() {
    std::function<int(int)> f = ([&f](int i){ return i?f(i-1)*i:1; }), trash = (std::cout << f(3) << std::endl, f);
}

However, I don't think it's a good idea to actually use this: The construct , trash = (..., f) would be in order for code golf or obfuscated programming contests, but would not meet my standards for production code.

like image 26
cmaster - reinstate monica Avatar answered Oct 31 '22 07:10

cmaster - reinstate monica


What you are essentially asking for is to create a temporary instance of std::function and then invoke operator() on that object in the same statement. Both of these fail to compile for me with the same error when I try that:

function<void(int)> f{[&f](int i){ if (i > 1) { cout << "func(a, "; f(i-1); cout << ")"; } else cout << "a"; }}(n);

function<void(int)> f([&f](int i){ if (i > 1) { cout << "func(a, "; f(i-1); cout << ")"; } else cout << "a"; })(n);

error: expected ‘,’ or ‘;’ before ‘(’ token

Pointing at the ( of (n).

See @Jarod42's answer for a viable workaround, if you don't mind the extra variable initialization.

Alternatively, this would work, though it does have to use separate variable declaration and assignment:

function<void(int)> f; f = [&f](int i){ if (i > 1) { cout << "func(a, "; f(i-1); cout << ")"; } else cout << "a"; }, f(n);

Demo

like image 25
Remy Lebeau Avatar answered Oct 31 '22 08:10

Remy Lebeau