可以用lambda参数遮蔽非捕获变量吗?

时间:2015-07-13 18:37:40

标签: c++ lambda shadow clang++

我有一个看起来像这样的代码 - 它被大大简化了,但是这个代码片段编译并表现出相同的行为:

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(

^

哪个不是很有用 - 我理解变量的阴影是什么,但是因为lambda没有捕获任何东西,所以在这里应该没问题。

我错过了什么?

2 个答案:

答案 0 :(得分:10)

是的,一个非捕获的变量可以被lambda参数遮蔽。

在OP中的lambda的特定情况下,你可能会争辩说value的内部声明不会影响外部声明的范围,因为lambda没有捕获。尽管如此,外部value可以在lambda的主体内部看到,因为lambda的主体仍在封闭块的范围内:

  

(C ++14§5.1.2/ p.7):lambda表达式的复合语句产生函数调用运算符的函数体(8.4),但 表示名称查找 (3.4),确定此类型和值(9.3.2),并使用(* this)(9.3.1)将引用非静态类成员的idexpressions转换为类成员访问表达式, 复合语句在lambda-expression 的上下文中被考虑。

来自外部作用域的非捕获变量的使用是一个错误,但是如果没有捕获的lambda可能会使用在外部作用域中定义的名称(如果它不是odr-use)(在这种情况下,变量捕获。)特别是,可以使用外部范围内的const变量:

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

因此即使lambda没有捕获,名为i的显式参数肯定会影响外部i。 (请参阅http://coliru.stacked-crooked.com/a/006f5f20cca841d5;您可能想尝试启用-Wshadow。)

由于-Wshadow正是为了揭示这种模糊的名称用法,因此在OP的情况下触发警告似乎并不令人惊讶。

-Wshadow未被-Wall-Wextra启用,因为它通常会警告您一些您并不真正关心的事情。

答案 1 :(得分:2)

你错过了编译器并不完美,有时会在相对较新的语言功能中发出愚蠢的警告,因为它们没有多大意义。

另一方面,警告通常都是关于确保真正意味着编写您编写的代码而不是其他代码。也许你的意思是抓住外面的value但是 - 无论出于何种原因:也许你没有注意 - 未能抓住它并重新声明它。

在这段看起来似乎有些延伸的代码中,但关键是警告不会始终告诉您所编写的代码:它们有时会告诉您编译器的代码认为你可能意味着写作。

然后用这个参数的不同名称来说“嘿,是的,我知道”是非常微不足道的。

这也可以提供更清晰的代码,并且有充分记录的意图。