Почему нельзя использовать переменные-члены без лямбды, если существуют незаписанные локальные переменные?

Простой пример:

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членская переменная.

Вопрос: Это ожидаемое поведение, и если да, то объясните, пожалуйста, почему?

7

Решение

От 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.
}();
}
1

Другие решения

Ошибка, которую вы получили, сказала:

ошибка: переменная ‘x’ не может быть неявно захвачена в лямбда-выражении без указания захвата по умолчанию

х = 6;

примечание: здесь объявлено «х»
void bar (int x) {
^
примечание: лямбда-выражение начинается здесь
это -> пустота {
^
предупреждение: приватное поле ‘x’ не используется [-Wunused-private-field] int x;

Что привело меня к тому, что проблема была в определении (или, точнее, переопределение) переменной x, Вы объявляете это как снаружи bar() и как параметр. Следующий код скомпилирован для меня (используя живой инструмент ты показал)

class Foo {
int x;

void bar() {
[this]() -> void {
x = 6;
}();
}
};

Надеюсь это поможет.

0

По вопросам рекламы [email protected]