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.
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.
But a lambda cannot be recursive, it has no way to invoke itself.
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.
This is an example of a function that will recursively call itself. Warning It's possible to run into infinite loops with recursive calls.
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
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With