Простой пример:
class Foo {
int x;
void bar(int x) {
[this]() -> void {
x = 6;
}();
}
};
Это не компилируется на GCC, Clang, MVC или ICC (увидеть это в прямом эфире). Если я изменю void bar(int x)
в void bar(int y)
или если я поменяю x = 6;
в this->x = 6;
тогда работает нормально.
Это не имеет смысла для меня. Локальная переменная x
от звонка до bar
намеренно не захвачен в лямбду. Единственный x
это имеет смысл Foo
членская переменная.
Вопрос: Это ожидаемое поведение, и если да, то объясните, пожалуйста, почему?
От cppreference:
В целях поиска имени, определения типа и значения
этот указатель и для доступа к нестатическим членам класса, тело
оператор вызова функции типа замыкания рассматривается в контексте
лямбда-выражения.
В теле метода bar (int x) токен «x» относится к аргументу метода, а НЕ к члену класса. Член скрыт.
[ПРИМЕЧАНИЕ, это, конечно, плохая практика кодирования, но не незаконная]
Если бы вы сказали x = 6
где у вас в настоящее время есть лямбда-определение, вы ожидаете, что локальная переменная x
(то есть передаваемый по значению аргумент методу), который нужно изменить, а не член x
, право?
Таким образом, единственный вопрос заключается в том, может ли локальная переменная неявно перехватываться лямбда-выражением? Я бы сказал, что компиляторы достаточно ясно объясняют, что это невозможно.
cppreference также проясняет это в этом утверждении:
Переменная может использоваться без перехвата, если она не имеет
длительность автоматического хранения (т.е. это не локальная переменная или
статический или локальный поток), или если он не используется в теле лямбды.
Примечание: odr-used означает, что вы должны знать адрес переменной, а не только ее значение. Присвоение значения переменной считается как использование odr.
Рассмотрим этот код:
class Foo {
int george;
void bar(int washington) {
int martha = washington;
washington = 7;
int jefferson = washington;
int adams = martha;
george = 6;
[this, jefferson]() -> void {
this->george = 15; // legal because `this` is captured
jefferson = adams; // legal because jefferson is explicitly
// captured, and because adams is not
// odr-used, so adams can be captured
// implicitly.
martha = 9; // not legal because it is an odr-use
// of a local variable so martha is not
// implicitly captured.
}();
}
Ошибка, которую вы получили, сказала:
ошибка: переменная ‘x’ не может быть неявно захвачена в лямбда-выражении без указания захвата по умолчанию
х = 6;
примечание: здесь объявлено «х»
void bar (int x) {
^
примечание: лямбда-выражение начинается здесь
это -> пустота {
^
предупреждение: приватное поле ‘x’ не используется [-Wunused-private-field] int x;
Что привело меня к тому, что проблема была в определении (или, точнее, переопределение) переменной x
, Вы объявляете это как снаружи bar()
и как параметр. Следующий код скомпилирован для меня (используя живой инструмент ты показал)
class Foo {
int x;
void bar() {
[this]() -> void {
x = 6;
}();
}
};
Надеюсь это поможет.