Сбой неявного захвата 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; }();
}();