Почему лямбда, определенная в методе, не может захватить переменную-член?
Рассмотрим следующий код:
class Object
{
public:
void method();
private:
bool field;
};
void Object::method()
{
auto lambda = [&field]()
{
// ....
};
}
Подскажите, пожалуйста, почему компилятор запрещает захватывать поле field?
Ответы (2 шт):
Захватывайте this. Все же field - не локальная переменная для method.
class Object
{
public:
void method();
private:
bool field;
};
void Object::method()
{
auto lambda = [this]()
{
this->field = !this->field;
};
cout << field << endl;
lambda();
cout << field << endl;
}
int main(int argc, const char * argv[])
{
Object obj;
obj.method();
}
Впрочем, не помню точно, с какой версии (14? 17?), но вполне допустим и такой вариант:
void Object::method()
{
auto lambda = [&f = this->field]() // И даже [&f = field]
{
f = !f;
};
cout << field << endl;
lambda();
cout << field << endl;
}
Это по дизайну так - члены класса явно не могут захватываться без инициализатора, только переменные могут.
Почитайте о capture list
Class members cannot be captured explicitly by a capture without initializer (as mentioned above, only variables are permitted in the capture list):
class S {
int x = 0;
void f() {
int i = 0;
// auto l1 = [i, x]{ use(i, x); }; // error: x is not a variable
auto l2 = [i, x=x]{ use(i, x); }; // OK, copy capture
i = 1; x = 1; l2(); // calls use(0,0)
auto l3 = [i, &x=x]{ use(i, x); }; // OK, reference capture
i = 2; x = 2; l3(); // calls use(1,2)
}
}
А связано это скорее всего с тем, что объекты из внешних для лямбды пространств имен, коим является field объявленный в пространстве имен класса Object не должны быть видны лямбде напрямую, в то время как this неявно передающийся каждому члену фукнции в качестве параметра содержится в пространстве имён (в Object::method) в котором создана лямбда, поэтому его можно захватывать.