Почему я не могу захватить это по ссылке ('&this') в лямбда?


Я понимаю, правильный способ захвата this (для изменения свойств объекта) в лямбде выглядит следующим образом:

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

но мне любопытно, что я видел следующую особенность:

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

странность, что я смущен (и хотел бы ответить), почему следующие работы:

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

и почему я не могу четко улавливать this ссылки:

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

2 ответа:

причина [&this] не работает, потому что это синтаксическая ошибка. Каждый разделенный запятыми параметр в lambda-introducer - это capture:

capture:
    identifier
    & identifier
    this

видно, что &this не допускается синтаксически. Причина, по которой это не разрешено, заключается в том, что вы никогда не захотите захватить this по ссылке, так как это небольшой указатель const. Вы только когда - нибудь захотите передать его по значению-так что язык просто не поддерживает захват this по ссылке.

для захвата this явно вы можете использовать [this] как lambda-introducer.

первый capture может быть capture-default что:

capture-default:
    &
    =

это означает автоматически, что я использую, по ссылке (&) или по значению (=) соответственно - однако лечение this является Специальным - в обоих случаях он захватывается значением по причинам, указанным ранее (даже при захвате по умолчанию &, что обычно означает захват ссылка.)

5.1.2.7/8:

для целей поиска имени (3.4), определения типа и значения this (9.3.2) и преобразование id- выражения, ссылающиеся на нестатические члены класса в выражения доступа к членам класса с помощью (*this) (9.3.1), составное утверждение [лямбды] рассматривается в контексте лямбда-выражения.

таким образом, лямбда действует так, как будто она является частью функции-члена enclosing при использовании имена членов (как в вашем примере использование имени x), поэтому он будет генерировать "неявные использования"this так же, как это делает функция-член.

если лямбда-захват включает в себя захват-значение по умолчанию, которое &, идентификаторы в лямбда-захвате не должны быть предшествует &. Если лямбда-захват включает в себя захват-значение по умолчанию, которое = лямбда-захват не должен содержать this и каждый идентификатор, который он содержит, должен предшествовать &. Идентификатор или this не должно появляться более попав в лямбда-захват.

так что вы можете использовать [this],[&],[=] или [&,this] как lambda-introducer захват this указатель на значение.

[&this] и [=, this] плохо сформированы. В последнем случае gcc прощающе предупреждает за [=,this] это explicit by-copy capture of ‘this’ redundant with by-copy capture default, а не ошибки.

потому что стандарт не имеет &this в списках захватов:

N4713 8.4.5.2 Захватывает:

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. для целей лямбда-захвата выражение потенциально ссылается на локальные сущности следующим образом:

    7.3 A это выражение потенциально ссылается на * this.

Итак, стандартные гарантии this и *this и &this является недействительным. Кроме того, захват this использование *this(что является lvalue, сам объект)по ссылке,, а не захват this указатель по стоимости!