2017-02-14 42 views
17

Próbuję skompilować następujący kod:Dlaczego konstruktor ruchu nie jest wywoływany podczas poruszania się w lambda?

#include <utility> 

struct C2 { 
     C2() = default; 
     C2(C2 const&) = delete; 
     C2(C2&&) = default; 
}; 

int main() { 
     C2 p2; 
     ([p2_1{ std::move(p2) }]() { 
       auto p2_2 = std::move(p2_1); // <--- 
     })(); 
     return 0; 
} 

Jednak to nie skompilować i daje błąd, że przypisanie do p2_2 dzwoni usuniętą funkcję, a mianowicie konstruktor kopiujący. Zauważ, że przejście na p2_1 jest w porządku. Dlaczego nie korzysta się z konstruktora ruchu?

+0

Nie jestem ekspertem od lambda, ale zamiast przenosić 'p2' na' p2_1', przechwytuję 'p2_1', a następnie przenoszę' p2_1' do 'p2_2', czemu nie wystarczy [uchwycić' p2' przez odwołanie i przenieść bezpośrednio do 'p2_2'] (http://ideone.com/PsBQMJ)? '[& p2]() {auto p2_2 = std :: move (p2); } ' –

+2

@RemyLebeau to znacznie uproszczona wersja tego, co faktycznie robiłem. Ciągle usuwałam części, dopóki nie dostałam małej próbki, która nadal ma problem. Rzeczywisty kod potrzebował lambda do przeżycia zakresu funkcji, w którym został zadeklarowany, więc wychwytywanie-po-ref nie wchodziło w grę. – baruch

+0

OK, to ma sens. –

Odpowiedz

27

Połów jest taki, że operator() anonimowego typu klasy domyślnie reprezentuje lambda const. Oznacza to, że nie można przenieść z p2_1, ponieważ this z lambda to const& w funkcji. Co trzeba zrobić, to użyć mutable słowa kluczowego jak

int main() { 
     C2 p2; 
     ([p2_1{ std::move(p2) }]() mutable { 
       auto p2_2 = std::move(p2_1); // <--- 
     })(); 
     return 0; 
} 

co sprawia, że ​​funkcja non const, co z kolei oznacza, że ​​można zmutować jego członków. Pozwala to przenieść p2_1 zamiast próbować go skopiować.

+0

Czy dotyczy to również przechwytywania "tego"? Wydaje mi się, że mogę wywoływać funkcje inne niż const za pomocą przechwyconego "tego" wskaźnika – baruch

+0

@baruch To jest dobre pytanie. AFAIK, gdy przechwycisz 'this', zachowuje swój typ wartości, więc jeśli nie jest const, to nie będzie stał w lambda. – NathanOliver

+3

@baruch 'this' jest const, ale' * this' nie jest. Jest to wskaźnik const, ale nie wskaźnik do stałej. – immibis