Мои параметры лямбды действительно затеняют моих местных жителей?
Я имею дело с кодом C, который берет некоторые данные и передает их функции, переданной в:
void foo(int* data, void (*fun)(int*)){
(*fun)(data);
};
Следующие работы без предупреждения:
void bar(int* data){};
int main(){
int data=0;
foo(&data,bar);
}
Однако, если я использую лямбду вместо:
int main(){
int data=0;
foo(&data,[](auto data){});
}
Я получаю следующее предупреждение:
warning: declaration of ‘data’ shadows a previous local [-Wshadow]
foo(&data,[](auto data){});
^
o.cpp:14:7: note: shadowed declaration is here
int data=0;
Но я думал, что пустая группа захвата исключит первое создание во время поиска.
Является ли это предупреждение законным?
Почему пустого захвата недостаточно, чтобы избежать предупреждений?
2 ответа
Имена из области охвата лямбды также входят в область действия лямбды.
Имена, которые не были захвачены, могут все еще использоваться, пока они не используются odr. Должны быть записаны только переменные, используемые odr. Пример:
#include <iostream>
template<typename T> void foo(const int *, T f) { std::cout << f(5) << '\n'; }
int main()
{
const int data=0;
foo(&data,[](int baz){
return data;
});
}
Поскольку чтение константного выражения не использует odr, этот код является правильным и data
относится к переменной в main
,
Эта программа выводит 0
, но если вы измените int baz
в int data
, это выводит 5
,
В отношении MISRA C++ 2008: идентификатор, объявленный во внутренней области видимости, никогда не должен иметь того же имени, что и идентификатор, объявленный во внешней области видимости.
В вашем примере int data
объявляется во внешней области видимости, но переходит во внутреннюю область видимости лямбды через ссылку. Проблема в том, что у вас также есть параметр в списке параметров вашей лямбды, называемый данными (внутренняя область). Это приводит к сокрытию переменной данных от внешней области видимости в лямбде.
Кстати. Также ваш первый пример с указателем на функцию должен быть переписан, потому что также существует конфликт с именами идентификаторов во внутренней и внешней области видимости. В этом случае это не так уж и плохо, потому что во внутренней оценке используется только одна переменная данных. Однако, когда переменные списка параметров и переменные из внешней области видимости, вызывающей функцию, имеют одно и то же имя, это может привести к путанице у программистов, и этого также следует избегать.