Сбой неявного захвата Lambda с переменной, объявленной из структурированной привязки
со следующим кодом я получаю ошибку компиляции C2065 'a': undeclared identifier
(С помощью visual studio 2017):
[] {
auto [a, b] = [] {return std::make_tuple(1, 2); }();
auto r = [&] {return a; }(); //error C2065
}();
однако следующий код компилируется:
[] {
int a, b;
std::tie(a, b) = [] {return std::make_tuple(1, 2); }();
auto r = [&] {return a; }();
}();
Я думал, что эти два образца эквивалентны. Это ошибка компилятора или я что-то пропустила ?
2 ответов
основной вопрос 2313 изменил стандарт так, что структурированные привязки никогда не являются именами переменных, что делает их никогда не захватываемыми.
P0588R1переформулировка лямбда захвата формулировки делает этот запрет явным:
если лямбда-выражение [...] захватывает структурированную привязку (явно или неявно), программа плохо сформированные.
отметим, что эта формулировка якобы заполнителя при комитет точно определяет, как должны работать такие захваты.
предыдущий ответ сохранен по историческим причинам:
это технически должно компилироваться,но здесь есть ошибка в стандарте.
стандарт говорит, что lambdas может захватывать только переменные. И он говорит, что не кортежное структурированное объявление привязки не вводит переменные. Он вводит имена, но эти имена не являются именами переменных.
A с другой стороны, кортежная структурированная декларация привязки, тут вводим переменные. a
и b
на auto [a, b] = std::make_tuple(1, 2);
фактические
ссылочные переменные. Чтобы их могла поймать лямбда.
очевидно, что это не вменяемое положение дел, и комитет это знает, поэтому исправление должно быть получено (хотя, как представляется, есть некоторые разногласия относительно того, как именно должен работать захват структурированной привязки).
возможным обходным путем является использование лямбда-захвата с инициализатором. Следующий код компилируется в Visual Studio 2017 15.5.
[] {
auto[a, b] = [] {return std::make_tuple(1, 2); }();
auto r = [a = a] {return a; }();
}();