Неявный захват константы

#include <iostream>

void bar(int x) { std::cout << x << '\n'; }

void foo() {
    const int x = 42;
    [](){ bar(x); }();
}

int main() { foo(); }

Почему программа компилируется, если x -- константа, и не компилируется в противном случае?

error: 'x' is not captured


Ответы (1 шт):

Автор решения: HolyBlackCat

Тут дело тонкое.

x - неявно constexpr, потому что она const, имеет целочисленный тип, и инициализируется константой времени компиляции. ([expr.const]/4 и выше)

Использование constexpr переменных в лямбде требует захвата только если вы используете адрес переменной (и переменная не глобальная и не статическая). Если вы используете только значение, а не адрес, в захвате нет необходимости. ([expr.prim.lambda.capture]/11)

Такое использование адреса constexpr переменной называется odr-использованием (odr-use) переменной (от слова one definition rule), и делает захват обязательным. Для не-constexpr переменной даже ее использование без взятия адреса считается odr-использованием, поэтому их захват обязателен в любом случае. (вроде бы [basic.def.odr]/4, но там на эльфийском, на cppreference понятнее)

Интересно, что если в лямбде указан захват по умолчанию - = или &, то даже не-odr-использование переменной в лямбде может вызвать ее захват, если компилятор это не соптимизирует, хотя в отсутствие = и & все работало бы без захвата. (пример в [expr.prim.lambda.capture]/7)

→ Ссылка