user1233963
user1233963

Reputation: 1490

Call lambda without binding it to an identifier

Browsing some internet board I encountered this little challenge:

"Implement a recursive anonymous function in your favorite language"

Obviously this is easy using a std::function/function pointer.

What I'm really interested in is if this is possible without binding the lambda to an identifier?

Something like (ignoring the obvious infinite recursion):

[](){ this(); }();

Upvotes: 7

Views: 1018

Answers (4)

nneonneo
nneonneo

Reputation: 179442

Of course, in C++, to call any function you have to bind it to an identifier somewhere, simply owing to syntax constraints. But, if you will accept parameters as being sufficiently unnamed, then it is possible to create a version of the y-combinator in C++ which recurses nicely without being "named".

Now, this is really ugly because I don't know how to do a typedef for a recursive lambda. So it just uses a lot of cast abuse. But, it works, and prints FLY!! until it segfaults due to stack overflow.

#include <iostream>

typedef void(*f0)();
typedef void(*f)(f0);

int main() {
    [](f x) {
        x((f0)x);
    } ([](f0 x) {
        std::cout<<"FLY!!\n";
        ((f)x)(x);
    });
}

The two lambdas are unnamed in the sense that neither is explicitly assigned to name anywhere. The second lambda is the real workhorse, and it basically calls itself by using the first lambda to obtain a reference to itself in the form of the parameter.

Here's how you would use this to do some "useful" work:

#include <iostream>

typedef int param_t;
typedef int ret_t;

typedef void(*f0)();
typedef ret_t(*f)(f0, param_t);

int main() {
    /* Compute factorial recursively */
    std::cout << [](f x, param_t y) {
        return x((f0)x, y);
    } ([](f0 x, param_t y) {
        if(y == 0)
            return 1;
        return y*((f)x)(x, y-1);
    }, 10) << std::endl;
}

Upvotes: 5

user1233963
user1233963

Reputation: 1490

I seem to have come up with a solution of my own:

#include <iostream>

int main()
{
    std::cout<<"Main\n";
    [&](){
        std::cout<<"Hello!\n";
        (&main+13)();
         }();
}

First call to cout is present just to show that it's not calling main.

I came up with the 13 offset by trial and error, if anyone could explain why it's this value it would be great.

Upvotes: 0

masoud
masoud

Reputation: 56479

No identifier for functions/methods, Close enough or not !?

struct A
{
    void operator()()
    {
        [&]()
        {
            (*this)();
        }();
    }
};

To call

A{}(); // Thanks MooningDuck

Upvotes: 1

Xeo
Xeo

Reputation: 131799

Are you allowed to cheat?

void f(){
  []{ f(); }();
}

It's recursive - indirectly, atleast.

Otherwise, no, there is no way to refer to the lambda itself without assigning it a name.

Upvotes: 3

Related Questions