2017-04-06 51 views
3

所以我有一个可变参数模板类,该类有一个模板参数在lambda中捕获的方法。稍后调用lambda。问题是,无论是在包装的正面还是在背面都会失去价值。当在一个lambda中捕获一个参数包时,一些ints会丢失它们的值

下面是一个简单的例子:

#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(); 
} 

这是输出我得到:

Test 1: 
1 
2 
3 

Test 2: 
32764 
2 

Test 3: 
1 
32764 

Test 4: 
1 
0 
3 

正如你所看到的,包裹整数始终保持自己的价值观,但整数有时穿上”吨。 我知道它的作品,如果我通过复制捕获和不使用前进,但我不能这样做在我的实际使用情况。

那么,为什么不工作?有什么方法可以解决它?

编辑:好吧,好吧,很明显,我是愚蠢的让变量超出范围在示例中。它适用于局部变量。但是,问题仍然出现在我的用例中,其中变量未超出范围。我会尝试将问题转移到我的示例,然后重试。

+0

我怀疑UB的某处,因为我得到了不同的[结果](http://ideone.com/qEg1g1)。 –

+8

'TestClass :: createWrapper()'捕获对局部变量的引用。 – aschepler

+1

作为扩展aschepler的评论,你会希望通过值来捕获参数,... wrapper = [=]() - > void .... – diverscuba23

回答

5

所以发生了什么事情是你的引用超出了范围,然后再使用它们。

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

你传递出去的时候范围的变量,你去

test1.wrapper(); 

,如果你将它们存储在本地话叫,像

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

它应该管用。对于您的实际代码,您需要确保 这些值从调用createWrapper到每次调用wrapper时仍然有效,或者您需要通过createWrapper中的值进行捕获。

编辑:

我错过了这一点:

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

为test1的你是不是在转发(x和z为上述我的例子),你转发x的副本通过INT的和z因为那些int值被传递。如果您更改为

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

那么我认为它会工作。

+0

*通过值* :你打算说*按价值捕获*。 – j6t

+0

好的。谢谢! – user7611475

+2

欢迎来到Stack Overflow。你会通过像这样的优秀答案在声望榜上巡游。 – Bathsheba

相关问题