Может ли лямбда не захватывать глобальные переменные?

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; }();
}