2015-07-13 2 views
4

У меня есть код, который выглядит следующим образом - это сильно упрощенная, но этот фрагмент компилирует и имеет такое же поведение:Может ли незахваченная переменная затеняться параметром лямбда?

template <typename TFunc> 
float FloatSelect(const float in_value, TFunc&& Predicate) { 
    return std::forward<TFunc>(Predicate)(in_value) ? in_value : 0.0f; 
}; 

void DisplayFloatSelect() { 
    const float value = FloatSelect(
    -1.0f, 
    [] (const float value) { return value > 0.0f; } 
); 

    std::cout << value << std::endl; 
} 

С -Wshadow включен компилятор выдает следующее предупреждение (как видно here):

12 : warning: declaration shadows a local variable [-Wshadow] 

[] (const float value) { return value > 0.0f; } 

^ 

10 : note: previous declaration is here 

const float value = FloatSelect(

^ 

Это не очень полезно - я понимаю, что затеняет переменную, но поскольку лямбда ничего не захватывает, здесь должно быть хорошо.

Что мне не хватает?

+6

Его полезно, потому что, возможно, вы хотели его захватить и нет (и вы не получаете [соответствующее сообщение об ошибке] (http://coliru.stacked-crooked.com/a/e2b67408a861b26d) из-за затенения) , – Borgleader

+0

Ничего, предупреждение не имеет смысла. –

+0

Вы использовали одно и то же имя переменной в двух вложенных контекстах, компилятор не знает, было ли это намеренно, поэтому оно дает предупреждение. Вот в чем смысл этого предупреждения. Оригинальное 'значение' находится в области тела лямбда, оно просто плохо сформировано, чтобы ссылаться на него, не захватывая его. –

ответ

9

Да, незахваченная переменная может быть затенена параметром лямбда.

В частном случае лямбда в OP вы можете утверждать, что внутреннее объявление value не затеняет область внешней декларации, поскольку лямбда не имеет захватов. Тем не менее, внешний value можно увидеть внутри тела лямбды, потому что тело лямбды все еще внутри рамки блока ограждающего:

(C++ 14 § 5.1.2/с.7): Составная заявка лямбда-выражения дает функциональное тело (8.4) оператора вызова функции, но для целей поиска по имени (3.4), определяя тип и значение этого (9.3.2) и преобразование idexpressions, относящихся к нестационарным членам класса, в выражения доступа к члену класса с использованием (* this) (9.3.1), составной оператор рассматривается в контексте лямбда-выражения.

ODR-использование не-захвачено переменный из внешней области является ошибкой, но это возможно для лямбды без захватов, чтобы сделать использование имени, определенным во внешней области видимости, если он не является ODR -use (и в этом случае переменная не захвачена.) В частности, можно использовать const переменные из внешней области:

const int i = 20; 
int f = ([](){return i + 3;})(); 

Таким образом, даже при том, что лямбда не имеет захватов, явный аргумент с именем i бы, конечно, теневой внешний i. (См http://coliru.stacked-crooked.com/a/006f5f20cca841d5, вы можете попробовать включить -Wshadow.)

С -Wshadow точно предназначен для выявления такого рода неоднозначного использования имени, это не кажется слишком удивительно, что это вызывает предупреждение в случае ОП ,

-Wshadow не включен ни -Wall, ни -Wextra именно потому, что он часто предупреждает вас о чем-то, о чем вас не беспокоит.

+0

Спасибо, это именно тот ответ, который я искал - этот код не очень приятен, но мне было любопытно узнать о причине предупреждения. Пример с константной переменной говорит сам за себя. – Gama

2

Вам не хватает того, что компиляторы не идеальны и иногда испускают глупые предупреждения относительно относительно новых языковых особенностей в обстоятельствах, когда они не имеют большого смысла.

С другой стороны, предупреждения часто касаются обеспечения того, чтобы вы действительно предназначались для написания кода, который вы написали, вместо какого-либо другого кода. Возможно, вы хотели захватить внешний value, но — по какой-то причине: возможно, вы не обратили внимание. — не удалось его захватить и вместо этого переобъявил.

В этом коде, который действительно кажется немного растянуть, но дело в том, что предупреждения не всегда сказать вам о коде вы написали: они иногда говорят вам о коде компилятор думает, что, возможно, означал, чтобы написать.

И вот довольно тривиально использовать другое имя для этого параметра, чтобы сказать «эй, да, я знаю».

Это также обеспечило бы более четкий код с хорошо документированным намерением.

+0

Где раздражающая часть «они иногда рассказывают вам о коде, который компилятор думает, что вы, возможно, предназначались для написания», нехорошо (попытка написать бесплатный код предупреждения) –

+0

@ DieterLücking: Чрезвычайно редко, что это не тривиально «исправлять». И, как правило, это происходит, когда ваш код был менее оптимальным. Я обратился к этому в ответ. –

Смежные вопросы