2012-04-23 21 views
12

私はC++ 11の新機能を学び、この問題に遭遇しました。私はfor_eachの引数としてラムダの中でそれを動かすことによってunique_ptrを捕捉したいと思います。std :: for_eachでlambdaのstd :: unique_ptrを "移動で"キャプチャする方法

を設定:

std::array<int,4> arr = {1,3,5,6}; 
std::unique_ptr<int> p(new int); (*p) = 3; 

試み1 - unique_ptrをコピーコンストラクタを持っていないため動作しませんが。 C++ 0xは、移動構文によるパスを指定しません。

std::for_each(arr.begin(), arr.end(), [p](int& i) { i+=*p; }); 

試み2 - 使用バインドint型&を取る関数へのpの移動コピーをバインドする:

std::for_each(arr.begin(), arr.end(), 
    std::bind([](const unique_ptr<int>& p, int& i){ 
      i += (*p); 
    }, std::move(p)) 
); 

コンパイラは、運動の'result' : symbol is neither a class template nor a function template.

主な目的はであることを訴えます後で使用するためにキャッシュされたラムダで可動変数をどのようにキャプチャするかを理解する。

+0

この質問は既に質問されています[ここ](http://stackoverflow.com/q/8640393/20984)。しかし、あなたの質問には代替的な(機能していませんが)解決策が含まれているので、私は投票には投票しません。 –

+0

[こちら](http://stackoverflow.com/q/8236521/20984)も参照してください。 –

答えて

18

更新:C++ 14以降のラムダの可動変数を取得することができます。

std::for_each(arr.begin(), arr.end(), [p=std::move(p)](int& i) { i+=*p; }); 

あなたはC++ 11のいずれかの簡単な方法でラムダに移動可能な変数をキャプチャすることはできません。

ラムダはコピーまたは参照によりキャプチャします。したがって、移動のみの変数をキャプチャするには、コピー=>移動するオブジェクト(たとえば、std::auto_ptr)にオブジェクトをラップする必要があります。これは厄介なハックです。

あなたの例では、あなただけの参照によって取り込むことができますが、これは単に簡略化されたコードだった場合、それはあなたが実際のコードを望んでないことがあります。

std::for_each(arr.begin(), arr.end(), [&p](int& i) { i+=*p; }); 

ここでコピー移動のみのラッパーです。

template<typename T> 
struct move_on_copy_wrapper 
{ 
    mutable T value; 

    move_on_copy_wrapper(T&& t): 
     value(std::move(t)) 
    {} 

    move_on_copy_wrapper(move_on_copy_wrapper const& other): 
     value(std::move(other.value)) 
    {} 

    move_on_copy_wrapper(move_on_copy_wrapper&& other): 
     value(std::move(other.value)) 
    {} 

    move_on_copy_wrapper& operator=(move_on_copy_wrapper const& other) 
    { 
     value=std::move(other.value); 
     return *this; 
    } 

    move_on_copy_wrapper& operator=(move_on_copy_wrapper&& other) 
    { 
     value=std::move(other.value); 
     return *this; 
    } 

}; 

あなたは、このようにそれを使用することができます:

int main() 
{ 
    std::unique_ptr<int> p(new int(3)); 
    move_on_copy_wrapper<std::unique_ptr<int>> mp(std::move(p)); 

    [mp]() 
    { 
     std::cout<<"*mp.value="<<*mp.value<<std::endl; 
    } 
    (); 

    std::cout<<"p="<<p.get()<<", mp="<<mp.value.get()<<std::endl; 
} 
+0

move_on_copy_wrapper(move_on_copy_wrapper &&)と 'move_on_copy_wrapper&operator =(move_on_copy_wrapper &&)'のようなmove-semantic関数を実装するには本当に必要ですか?コンパイラで生成されたものでは不十分ですか? – Nawaz

+1

コピーコンストラクタとコピー代入演算子の存在により、コンパイラはそれらを生成しません。 –

+1

"std :: bindでは引数もコピー可能である必要があります。それは真実ではない。 'std :: bind'はmove-only型で使えます。 –

2

あなたの試み2は、アルモますst仕事。何が不足しているか

は、パラメータを期待するあなたのbindコールを告げていないです。

std::for_each(arr.begin(), arr.end(), 
    std::bind([](const unique_ptr<int>& p, int& i){ 
     i += (*p); 
    }, std::move(p), std::placeholders::_1) 
); 

placeholders::_1が、それはそのoperator()のためにそれに渡されたパラメータを期待すべきbindの結果を伝えることが必要です。

これはまた、@ marton78の回答hereで提案されています。

関連する問題