2013-05-01 12 views
49

Rozumiem prawidłowy sposób, aby uchwycić this (modyfikowanie właściwości obiektu) w lambda jest w następujący sposób:Dlaczego nie mogę uchwycić tego odniesienia ("& this") w lambda?

auto f = [this]() { /* ... */ }; 

Ale jestem ciekaw, w następującym osobliwość widziałem:

class C { 
    public: 
     void foo() { 
      // auto f = []() { // this not captured 
      auto f = [&]() { // why does this work? 
      // auto f = [&this]() { // Expected ',' before 'this' 
      // auto f = [this]() { // works as expected 
       x = 5; 
      }; 
      f(); 
     } 

    private: 
     int x; 
}; 

kuriozum, że jestem zdezorientowany (a chciałby odpowiedzi) Dlatego następujące prace:

auto f = [&]() { /* ... */ }; // capture everything by reference 

i dlaczego nie mogę jednoznacznie capt URE this przez odniesienie:

auto f = [&this]() { /* ... */ }; // a compiler error as seen above. 
+3

Po co miałbyś ochotę? Pod względem rzeczy, dla których odniesienie do wskaźnika może być w ogóle użyteczne: "tego" nie można zmienić, nie jest ono wystarczająco duże, aby odwołać się szybciej ... i ** tak czy inaczej **, _ it doesn ' t faktycznie istnieje, więc nie ma prawdziwego życia, co oznacza, że ​​każde odniesienie do niego będzie zwisające z definicji. 'ten' jest prwartością, a nie lwartością. –

Odpowiedz

64

Powodem [&this] nie działa, ponieważ jest to błąd składni. Każdy parametr oddzielone przecinkami w lambda-introducer jest capture:

capture: 
    identifier 
    & identifier 
    this 

Widać, że nie jest dozwolone &this składniowo. Powodem, dla którego nie jest to dozwolone, jest to, że nigdy nie chcesz przechwytywać this przez odniesienie, ponieważ jest to mały wskaźnik const. Zawsze chciałbyś przekazać ją według wartości - więc język po prostu nie obsługuje przechwytywania this przez odniesienie.

Aby przechwycić this jawnie można użyć [this] jako lambda-introducer.

Pierwszy capture może być capture-default który jest:

capture-default: 
    & 
    = 

oznacza wychwytywania automatycznie co użyć przez odniesienie (&) lub wartości (=), odpowiednio, - jednak leczenie this jest szczególna - w obu przypadkach jest on przechwytywany przez wartość z powodów podanych wcześniej (nawet przy domyślnym przechwytywaniu &, co zwykle oznacza przechwytywanie przez odniesienie).

5.1.2.7/8:

Dla celów wyszukiwania nazw (3.4), określenie rodzaju i wartości this (9.3.2) i przekształcania id- wyrażenia odnoszące się do non-statycznych członków klasy w wyrażenia dostępu do członów klasy za pomocą (*this) (9.3.1), , złożoną instrukcję [OF THE LAMBDA] rozpatruje się w kontekście wyrażenia lambda.

Więc lambda działa tak, jakby jest częścią otaczającej funkcji składowej przy użyciu nazwy elementu (jak w przykładzie użycia nazwy x), więc będzie generować „ukryte zwyczaje” o this podobnie jak funkcja członkowska ma.

Jeżeli lambda-capture zawiera przechwytywania-default, które jest &, identyfikatory w lambda-wychwytywania nie będą poprzedzone &.Jeżeli przechwytywanie lambda obejmuje domyślne ustawienie przechwytywania, to jest =, przechwytywanie lambda nie może zawierać this, a każdy jego identyfikator musi być poprzedzony przez &. Identyfikator lub this nie powinien pojawiać się więcej niż jeden raz w wychwycie lambda.

Więc można użyć [this], [&], [=] lub [&,this] jako lambda-introducer uchwycić wskaźnik this przez wartość.

Jednak [&this] i [=, this] są źle sformułowane. W ostatnim przypadku gcc wybacza ostrzegawczo dla [=,this], że zamiast błędów.

+0

Zastanawiam się, czy istnieje jakikolwiek powód, by nie używać ani '[&] ani ani [=]'? Dlaczego miałbym chcieć jawnie określać identyfikatory, jeśli kompilator jest w stanie samodzielnie samodzielnie określić, co przechwycić? –

+3

@KonradRudolph: A jeśli chcesz uchwycić niektóre rzeczy według wartości i inne przez odniesienie? Lub chcesz być bardzo jednoznaczny z tym, co przechwytujesz? – Xeo

+1

@KonradRudolph: To funkcja bezpieczeństwa. Możesz przypadkowo uchwycić nazwiska, których nie chcesz. –

0

Ponieważ norma nie ma &this w połowach wymienia:

N4713 8.4.5.2 Przechwytuje:

lambda-capture: 
    capture-default 
    capture-list 
    capture-default, capture-list 

capture-default: 
    & 
    = 
capture-list: 
    capture...opt 
    capture-list, capture...opt 
capture: 
    simple-capture 
    init-capture 
simple-capture: 
    identifier 
    &identifier 
    this 
    * this 
init-capture: 
    identifier initializer 
    &identifier initializer 
  1. dla celów przechwytywanie lambda, wyrażenie potencjalnie odwołuje się do jednostek lokalnych w następujący sposób:

    7.3 To wyrażenie potencja lly referencje * to.

Tak, standardowe gwarancje this i *this jest ważny, a &this jest nieprawidłowy. Ponadto, przechwytywanie this oznacza przechwytywanie *this (co jest lwartość, sam obiekt) przez odniesienie, zamiast przechwytywanie this wskaźnik wartością!

+0

to nie dodaje niczego, co nie jest już w innej odpowiedzi –

+0

@AnthonySottile Ostatni akapit ma na celu poprawienie odpowiedzi. – czxyl

+0

Czy ktoś, kto głosuje, może mi podać powody? – czxyl

Powiązane problemy