When capturing a package of parameters in a lambda, some indexes lose their value

So, I have a variadic templating class that has a method where the arguments for the template are captured into a lambda. Later called lambda. The problem is that ints that are either in front or behind the package lose their meaning.

Here's a simplified example:

#include <iostream>
#include <functional>

void doPrint() {}

template <typename Arg, typename... Args>
void doPrint(Arg arg, Args... args) {
    std::cout << arg << std::endl;
    doPrint(std::forward<Args>(args)...);
}

template <typename... Args>
void print(Args... args) {
    doPrint(std::forward<Args>(args)...);
}

class IntWrapper {
public:
    IntWrapper(int val) : val(val) {}

    int val;
};

std::ostream& operator<<(std::ostream& out, const IntWrapper& value) {
    out << value.val;
    return out;
}


template <typename... Args>
class TestClass {
public:
    void createWrapper(Args... args) {
        wrapper = [&]() -> void {
            print(std::forward<Args>(args)...);
        };
    }

    std::function<void()> wrapper;
};

int main(int argc, char *argv[])
{
    std::string string = "abc";

    std::cout << "Test 1:" << std::endl;

    TestClass<int, const IntWrapper&, int> test1;
    test1.createWrapper(1, IntWrapper(2), 3);
    test1.wrapper();

    std::cout << std::endl << "Test 2:" << std::endl;

    TestClass<int, const IntWrapper&> test2;
    test2.createWrapper(1, IntWrapper(2));
    test2.wrapper();

    std::cout << std::endl << "Test 3:" << std::endl;

    TestClass<const IntWrapper&, int> test3;
    test3.createWrapper(IntWrapper(1), 2);
    test3.wrapper();

    std::cout << std::endl << "Test 4:" << std::endl;

    TestClass<const IntWrapper&, int, const IntWrapper&> test4;
    test4.createWrapper(IntWrapper(1), 2, IntWrapper(3));
    test4.wrapper();
}

      

This is the result I am getting:

Test 1:
1
2
3

Test 2:
32764
2

Test 3:
1
32764

Test 4:
1
0
3

      

As you can see, wrapped ints always keep their values, but ints sometimes don't. I know this works if I write in a copy and don't use a forward, but I can't seem to do it in my actual use case.

So why doesn't this work? And is there a way to fix this?

EDIT: Okay, well, obviously I was stupid in letting variables go out of scope in the example. It works with local variables. However, the problem still occurs in my use case where the variables are not out of scope. I'll try to transfer the problem to my example and try again.

+3


source to share


1 answer


So what happens is that your links go out of scope before using them.

test1.createWrapper(1, IntWrapper(2), 3);

      

all those variables you passed are out of scope by the time you get it

test1.wrapper();

      

if you saved them locally and then called, something like

int x = 1, z = 3; IntWrapper y(2); test1.createWrapper(x, y, z); test1.wrapper();

it should work. For your actual code, you either need to make sure the values ​​are still valid when you call createWrapper every time you call the wrapper, or you need to write by value to createWrapper.



Edit:

I missed this:

TestClass<int, const IntWrapper&, int> test1;

      

for test1, you are not forwarding the passed int (x and z in my example above), you are forwarding a copy of x and z, because those int are passed by value. If you change to

TestClass<int&, const IntWrapper&, int&> test1;

      

then i think it will work.

+5


source







All Articles