Lambda-captured variable reset

I am trying to use lambdainside a project, but I think that I have something missing in the closing area. I tested this piece of code that somehow simplifies my problem.

#include <iostream>
#include <functional>

using namespace std;

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

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

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

    tester(getNum);
    tester(getNum);
}

After the first call, the testercaptured variable starteris reset, so the same output is printed twice.

What should I do to avoid this internal counter ( starter) lambda behavior ? In fact, the second call testershould print 10 numbers, starting with 12 instead of 2.


EDIT

Thanks for answers. I did not think I was passing a copy tester_wrapper, so I found this solution:

#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 = ([](int starter) {
        return [starter]() mutable {
            return ++starter;
        };
    })(1);*/

    auto getNum = mylambda(1);

    tester(getNum);
    tester(getNum);
}

, getNum , "" , mylambda.

( ?)

+1
3

reset, . , . - . std::function. , , . tester . - std::reference_wrapper.

tester(std::ref(getNum));
tester(std::ref(getNum));

- , -, getNum.

, , , getNum, std::function , , , . , . , tester , tester_wrapper . , , , API.

+2

starter, , :

auto starter = 0;

auto getNum = [&starter]() {
    return ++starter;
};

:

tester(getNum);
tester(getNum);

1 20.

+2

The argument getNumyou pass in testeris copied std::function<int(void)>. That is, it std::function<int(void)>does not save the source getNum, instead it saves a copy.

@StoryTeller and @Edgar have already proposed two solutions. Here is the third one:

template<typename Callback>
void tester_wrapper(Callback && cb, int counter){
    if (counter == 10)
        return;
    else{
        cout << cb() << endl;
        tester_wrapper(cb, counter + 1);
    }
}

template<typename Callback>
void tester(Callback && cb){
    tester_wrapper(std::forward<Callback>(cb), 0);
}

Now there is no copy, since both functions take an argument by reference.

By the way, this code is likely to be faster than the other two, as the other two continue to use std:function, which has one virtual call or equivalent to call the stored caller.

Hope this helps.

+2
source

Source: https://habr.com/ru/post/1692174/


All Articles