c #lambda #scope
#c #c 11 #лямбда #глобальные переменные #стандарты
Вопрос:
int n;
int main()
{
[](){ n = 0; }(); // clang says "ok"
int m;
[](){ m = 0; }(); // clang says "not ok"
}
Мне просто интересно:
Если лямбда-выражение ничего не фиксирует, разрешено ли ему получать доступ к глобальным переменным в соответствии со стандартом C ?
Комментарии:
1. Я бы предположил, что это так, учитывая, что вы можете использовать другие глобальные вещи (функции и типы), не захватывая их. Представьте, если бы вам пришлось захватывать функции алгоритма C (
std::find
например), чтобы использовать их из лямбд.2. en.cppreference.com/w/cpp/language/lambda говорит о чем — то
capture-default
таком . Я не мог подробно разобраться, что он делает.3. Если вы подумаете об этом, лямбда-выражение — это просто короткий путь к определению a
struct
с помощью оператора функции. Локальные переменные не входят в областьstruct
видимости функций-членов, но глобальные переменные есть.4. Глобальные переменные не могут быть захвачены.
5. @cpplearner «Глобальные переменные не могут быть захвачены».? Любая ссылка?
Ответ №1:
Да, конечно. Применяются обычные правила поиска имен.
[expr.prim.lambda]/7 … для целей поиска имен… составная инструкция рассматривается в контексте лямбда-выражения.
Re: почему локальные переменные обрабатываются иначе, чем глобальные.
[expr.prim.lambda]/13 … Если лямбда-выражение или создание экземпляра шаблона оператора вызова функции универсального лямбда-odr-uses (3.2)
this
или переменная с автоматической продолжительностью хранения из области ее достижения, эта сущность должна быть захвачена лямбда-выражением.[expr.prim.lambda]/9 Лямбда-выражение, наименьшей объемлющей областью которого является область блока (3.3.3), является локальным лямбда-выражением… Область действия локального лямбда-выражения — это набор охватывающих областей вплоть до самой внутренней охватывающей функции и ее параметров включительно.
В вашем примере m
это переменная с автоматической продолжительностью хранения из области действия лямбды, и поэтому она должна быть захвачена. n
нет, и поэтому не должно быть.
Комментарии:
1. В приведенной цитате ничего не говорится о глобальных переменных.
2. Если
n
локально, код является незаконным. Почему это законно, еслиn
является глобальным?3. @xmllmx добавил объяснение того, почему локальные переменные ведут себя по-разному.
Ответ №2:
На самом деле [](){ n = 10; }();
он ничего не фиксирует, вместо этого он использует глобальную переменную.
int n;
int main()
{
[](){ n = 10; }(); // clang says "ok"
std::cout << n; // output 10
}
Смотрите capture-list в пояснении
список захвата — список, разделенный запятыми, из нуля или более захватов, необязательно начинающийся с захвата по умолчанию.
Список захвата можно передать следующим образом (подробное описание см. Ниже):
- [a,amp; b] где a захватывается копией, а b захватывается ссылкой.
- [this] фиксирует текущий объект (* this) по ссылке
- [amp;] фиксирует все автоматические переменные, используемые в теле лямбда-выражения, по ссылке и текущий объект по ссылке, если он существует
- [=] фиксирует все автоматические переменные, используемые в теле лямбда-выражения, путем копирования и текущего объекта по ссылке, если существует
- [ ] ничего не фиксирует
Комментарии:
1. » текущий объект по ссылке , если он существует»? Что это? Не могли бы вы объяснить это более подробно?
Ответ №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; }();
}