Может ли лямбда не захватывать глобальные переменные?
int n;
int main()
{
[](){ n = 0; }(); // clang says "ok"
int m;
[](){ m = 0; }(); // clang says "not ok"
}
Мне просто интересно:
Если лямбда ничего не фиксирует, разрешено ли доступ к глобальным переменным в соответствии со стандартом C++?
Ответы
Ответ 1
Да, конечно. Обычные правила поиска имен применяются.
[expr.prim.lambda]/7... для целей поиска имени... составной оператор рассматривается в контексте лямбда-выражения.
Re: почему локальные переменные обрабатываются иначе, чем глобальные.
[expr.prim.lambda]/13... Если лямбда-выражение или экземпляр шаблона оператора вызова функции общего лямбда-odr использует (3.2) this
или переменную с автоматическим временем хранения от ее области охвата, это субъект должен быть захвачен лямбда-выражением.
[expr.prim.lambda]/9 Лямбда-выражение, наименьшей охватывающей областью которого является область блока (3.3.3), является локальным лямбда-выражением... Область охвата локального лямбда-выражения представляет собой набор охватывающих областей до и включая самую внутреннюю закрывающую функцию и ее параметры.
В вашем примере m
- это переменная с автоматической продолжительностью хранения из области охвата лямбда и поэтому должна быть зафиксирована. n
не является, и поэтому не обязательно.
Ответ 2
На самом деле [](){ n = 10; }();
[](){ n = 10; }();
ничего не захватывает, вместо этого он использует глобальную переменную.
int n;
int main()
{
[](){ n = 10; }(); // clang says "ok"
std::cout << n; // output 10
}
См. Список захвата в Объяснении
capture-list - список с нулевым или большим количеством разделенных запятыми, необязательно начинающийся с по умолчанию-захвата.
Список захвата можно передать следующим образом (см. Ниже подробное описание):
- [a, & b], где a захватывается копией и b захватывается по ссылке.
- [this] захватывает текущий объект (* this) ссылкой
- [&] фиксирует все автоматические переменные, используемые в теле лямбда по ссылке и текущему объекту по ссылке, если существует
- [=] фиксирует все автоматические переменные, используемые в теле лямбда, копией и текущим объектом по ссылке, если существует
- [] ничего не фиксирует
Ответ 3
По умолчанию доступны глобальные, статические и константные переменные:
#include <iostream>
int n;
int main()
{
[](){ n = 10; }();
std::cout << n << std::endl;
static int m = 1;
[](){ m = 100; }();
std::cout << m << std::endl;
const int l = 200;
[](){ std::cout << l << std::endl; }();
}