2012-04-23 84 views
12

Poznaję nowe funkcje w C++ 11 i natrafiłem na ten problem. Chciałbym uchwycić unique_ptr, przesuwając go wewnątrz lambda jako argument dla for_each.Jak przechwytywać std :: unique_ptr "by move" dla lambda w std :: for_each

skonfigurować:

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

próbę 1 - nie działa, ponieważ unique_ptr nie posiada konstruktor kopiujący. C++ 0x nie określa składni przez przenoszenie składni.

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

próba 2 - wykorzystanie wiążą się wiązać przeniesiona kopię p do funkcji, która zajmuje int &:

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

Kompilator narzeka, że ​​'result' : symbol is neither a class template nor a function template.

Głównym celem ćwiczenia jest zrozumieć, w jaki sposób zmienna ruchoma może być przechwycona w lambda, która jest buforowana do późniejszego użycia.

+0

To pytanie zostało już zadane [tutaj] (http://stackoverflow.com/q/8640393/20984). Nie głosuję jednak, aby zamknąć, ponieważ twoje pytanie zawiera alternatywne (choć nie działające) rozwiązanie. –

+0

Zobacz także [tutaj] (http://stackoverflow.com/q/8236521/20984). –

Odpowiedz

18

Aktualizacja: możesz przechwycić zmienną ruchomą w lambda z C++ 14 lub późniejszej.

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

Nie można uchwycić zmienną ruchomy do lambda w jakikolwiek bezpośredni sposób w C++ 11.

Lambdas przechwytywanie przez kopiowanie lub przez odniesienie. Aby uchwycić zmienną tylko ruchową, należy ją zawinąć w obiekt, w którym kopiowanie => ruchome (takie jak std::auto_ptr). To jest paskudny hack.

w przykładzie, można po prostu uchwycić poprzez odniesienie, ale jeśli było to tylko uproszczony kod nie może zrobić, co chciał z rzeczywistym kodu:

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

Oto kopia-move-tylko wrapper:

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; 
    } 

}; 

następnie można go używać tak:

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

Czy naprawdę * potrzebujesz * do implementacji funkcji przenoszenia-semantycznej, tzn. 'Move_on_copy_wrapper (move_on_copy_wrapper &&)' i 'move_on_copy_wrapper & operator = (move_on_copy_wrapper &&)'? Wygenerowane przez kompilator nie wystarczą? – Nawaz

+1

Kompilator nie wygeneruje ich z powodu istnienia konstruktora kopiowania i operatora przypisania kopiowania. –

+1

"Zauważ, że std :: bind wymaga również, aby jego argumenty były kopiowalne." To nieprawda. 'std :: bind' jest użyteczne z typami tylko do ruchu. –

2

Twoja próba 2 będzie Almo st praca.

Czego brakuje to nie powiedziałeś wezwanie bind oczekiwać parametr:

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 trzeba powiedzieć wynik bind że powinien oczekiwać parametr przekazany do niego na swojej operator().

Jest to również sugestia podana w odpowiedzi @ marton78 na here.

Powiązane problemy