Вывод лямбда-типов захвата - PullRequest
9 голосов
/ 28 июня 2019

Я недавно обнаружил, что захват объекта const по значению в лямбда-выражении означает, что переменная внутри тела labmda (т. Е. Член данных лямбда-выражения) также имеет значение const.
Например:

const int x = 0;
auto foo = [x]{
  // x is const int
};

Это поведение упоминается в п. 8.1.5.2 в черновике для C ++ 17 :

Для каждого объекта, захваченного копией, неназванный не-статический член данных объявлен в типе замыкания.Порядок объявления этих членов не уточняется.Тип такого члена данных является ссылочным типом, если объект является ссылкой на объект, lvalue-ссылкой на ссылочный тип функции, если объект является ссылкой на функцию, или типом соответствующего захваченного объектав противном случае .Член анонимного объединения не может быть перехвачен копией.

Я ожидаю, что тип получаемых переменных будет таким же, как и вывод auto.
Есть ли веская причина для различенияправила вывода типов для захваченных типов?

Ответы [ 3 ]

7 голосов
/ 28 июня 2019

В вашем примере было бы невозможно изменить x, так как лямбда не mutable, что делает оператор вызова функции const. Но даже если лямбда равна mutable, верно, что цитируемый отрывок делает тип x в лямбде const int.

Если я правильно помню, это было преднамеренное решение в C ++ 11, чтобы использование x в лямбда-выражении велось аналогично использованию x во вложенной области видимости. То есть

void foo(int&);
void foo(const int&);
const int x = 0;
foo(x);  // calls foo(const int&)
auto foo = [x]() mutable {
    foo(x);  // also calls foo(const int&)
};

Это помогает избежать ошибок, когда, например, некоторый код переписывается с явного цикла на вызов алгоритма стандартной библиотеки с лямбда-выражением.

Если я ошибаюсь в этом воспоминании, надеюсь, кто-то с правильным ответом вступит и напишет свой собственный ответ.

1 голос
/ 28 июня 2019

Не ответ на рассуждения;Здесь уже есть исчерпывающий ответ здесь .

Для тех, кто хочет знать, как перехватить неконстантную копию переменной const, вы можете использовать перехват с инициализатором:

const int x = 0;
auto foo = [x = x]() mutable {
    // x is non-const
};

Для этого требуется C ++ 14.C ++ 11-совместимое решение - сделать копию вне лямбды:

const int x = 0;
int copy = x;
auto foo = [copy]() mutable {
    // copy is non-const
};
0 голосов
/ 28 июня 2019

Причина в том, что operator() в лямбде равно const по умолчанию.

int main()
{
    const int x = 0;
    auto foo = [x](){}; // main::$_0::operator()() const
    foo();
}

Итак, вы должны использовать mutable лямбда:

int main()
{
    const int x = 0;
    auto foo = [x=x](){}; // main::$_0::operator()()
    foo();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...