2017-04-06 3 views
3

したがって、テンプレートの引数がラムダでキャプチャされるメソッドを持つvariadicテンプレートクラスがあります。後でラムダが呼び出されます。問題は、パックの前部または後部にあるintがその価値を失うことです。ここでラムダでパラメータパックをキャプチャするときにint値が失われる

は簡単な例です:

#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 

あなたが見ることができるように、包まれたint型は常にその値を保持しますが、int型は時々ドン」 t。 コピーでキャプチャしてフォワードを使用しないとうまくいくことは分かっていますが、実際のユースケースではそれを行うことはできません。

なぜ、これは機能しませんか?それを修正する方法はありますか?

編集:さて、明らかに、私は変数がこの例の範囲外になるようにすることで愚かになりました。ローカル変数で動作します。しかし、変数はスコープ外ではない私のユースケースではまだ問題が発生します。私は問題を私の例に移して、もう一度やり直そうとします。

+0

私は別の[結果](http://ideone.com/qEg1g1)を取得しているので、私はUBをどこかに疑っています。 –

+8

'TestClass :: createWrapper()'はローカル変数への参照をキャプチャしています。 – aschepler

+1

拡張ascheplerのコメントとして、あなたは値で引数を取りたいと思うでしょう。... wrapper = [=]() - > void .... – diverscuba23

答えて

5

だから、あなたの参照が使用される前に範囲が外れているということです。

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

あなたがローカルに保存されている場合、それは

int x = 1, z = 3; IntWrapper y(2); test1.createWrapper(x, y, z); test1.wrapper();のようなもの

、と呼ばれるあなたは

test1.wrapper(); 

に着く時間によって範囲の外に出る渡され、これらの変数のすべてうまくいくはずです。実際のコードでは、ラッパーを呼び出すたびにcreateWrapperを呼び出すときに値が有効であることを確認するか、createWrapperで値を取得する必要があります。

編集:

私はこの逃した:あなたはxのコピーを転送しているあなたは(上記の私の例ではXとZ)に渡されたint型のを転送していないtest1のため

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

をし、これらのintは値渡されているからです。

に変更すると、
TestClass<int&, const IntWrapper&, int&> test1; 

と表示されます。

+0

*値渡し*あなたは値*でキャプチャを言うことを意味しました。 – j6t

+0

良いキャッチ。ありがとう! – user7611475

+2

ようこそスタックオーバーフロー。あなたはこのような優れた答えで評判リーグテーブルを巡ってクルーズします。 – Bathsheba

関連する問題