Почему я не могу захватить это по ссылке ('&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 ответа:
причина
[&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
для целей лямбда-захвата выражение потенциально ссылается на локальные сущности следующим образом:
7.3 A это выражение потенциально ссылается на * this.
Итак, стандартные гарантии
thisи*thisи&thisявляется недействительным. Кроме того, захватthisиспользование*this(что является lvalue, сам объект)по ссылке,, а не захватthisуказатель по стоимости!