Marco Luzzara
Marco Luzzara

Reputation: 6046

Different definitions of the same lambda

I've recently opened this discussion, from which the following problem comes from. This question is a sort of continuous of that discussion. Here is the code:

#include <iostream>
#include <functional>

using namespace std;

std::function<int(void)> mylambda(int starter){
    return [starter]() mutable {
        return ++starter;
    };
}

void tester_wrapper(const std::function<int(void)>& cb, int counter){
    if (counter == 10)
        return;
    else{
        cout << cb() << endl;
        tester_wrapper(cb, counter + 1);
    }
}

void tester(const std::function<int(void)>& cb){
    tester_wrapper(cb, 0);
}

int main()
{
    auto getNum = mylambda(1);

    tester(getNum);
    tester(getNum);
}

In this case the code does what I expected, more specifically it prints all number from 2 to 21. However if my main function was like this:

int main()
{
    auto getNum = ([](int starter) {
        return [starter]() mutable {
            return ++starter;
        };
    })(1);

    tester(getNum);
    tester(getNum);
}

Then the output would be numbers from 2 to 11 repeated twice. I can't explain myself why it produces this output even if the only difference between the 2 pieces of code is where and how the mylambda function is defined.

Upvotes: 5

Views: 216

Answers (1)

Because the lambda closure type and std::function are not reference related. Those are separate types. You can't bind a reference to std::function directly to a lambda object.

A lambda object is convertible to a std::function however. So what happens is that the compiler creates a temporary std::function that binds to that const reference. Creating very much the same situation in your original question. Because each call to tester necessitates another temporary object. Temporaries only live to the end of the full expression that makes them spring to life.

In the first code sample, you already have a std::function object in main. That one binds directly to the reference, so you are calling tester with the same referred-to object.

Upvotes: 8

Related Questions