Почему этот код не скомпилируется с gcc 4.8.5, в то время как он прекрасно компилируется с помощью clang - PullRequest
0 голосов
/ 27 июня 2018
#include<iostream>                                                                                                                                    

using namespace std;                                                                                                                                  

int main()                                                                                                                                            
{                                                                                                                                                     
   const int k = 10;                                                                                                                                  

   // Capture k by value                                                                                                                              
   auto myl = [k] (int k) { cout << " ++k=" << ++k ; };                                                                                            

   myl(k+10);                                                                                                                                             
}  

Ошибка ниже

lamda.cpp: In lambda function:
lamda.cpp:10:50: error: increment of read-only variable âkâ
    auto myl = [k] (int k) { cout << " ++K=" << ++k ; };

ясно, что я имею в виду локальную переменную K, а не постоянный член K.

1 Ответ

0 голосов
/ 29 июня 2018

Это не так просто, как может показаться. Лямбда, которая захватывает k при копировании, в основном эквивалентна объекту struct, тип замыкания которого имеет член с именем k и с operator(), в определении которого используются указанные параметры и тело. Если бы это было технически верно, конечно, мы знаем, что параметр функции скрывает член класса.

За исключением того, что Стандарт не определяет лямбды. Вместо этого он говорит, что любой объект, захваченный значением, соответствует безымянному члену типа замыкания. В лямбда-теле, поиск имени выглядит в области охвата лямбды, а не в типе замыкания. Если при поиске этого имени обнаруживается объект, захваченный копией, компилятор должен внутренне преобразовать это использование имени в использование безымянного члена. В C ++ 11 и C ++ 14 эти правила не четко указывали, как имена лямбда-параметров вписываются в эту схему поиска имен, и в результате различные компиляторы и версии компиляторов не соглашались с поведением в случаях, подобных этому, где захваченный объект и лямбда-параметр имеют одно и то же имя.

С помощью Устранение дефектов 2211 , C ++ 17 решил проблему, просто сделав ее незаконной:

[expr.prim.lambda.capture] / 5:

Если идентификатор в simple-capture отображается как идентификатор объявления параметра лямбда-объявления ' s параметр-объявление-предложение , программа некорректна. [ Пример:

void f() {
  int x = 0;
  auto g = [x](int x) { return 0; } // error: parameter and simple-capture have the same name
}

- конец примера ]

(См. Также тот же абзац в текущем черновом зеркале.)

...