lambda 参数可以隐藏非捕获变量吗?
Can a non-captured variable be shadowed by a lambda parameter?
我有一个看起来像这样的代码 - 它被大大简化了,但是这个片段编译并表现出相同的行为:
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 不捕获任何内容,因此在这里应该没问题。
我错过了什么?
您没有注意到编译器并不完美,有时会在相对较新的语言功能没有多大意义的情况下发出愚蠢的警告。
另一方面,警告通常都是为了确保您真的打算编写您编写的代码,而不是其他代码。也许您打算捕获外部 value
但是 — 无论出于何种原因:也许您没有注意 — 未能捕获它并重新声明它。
在这段代码中,这看起来确实有点牵强,但重点是警告并不总是告诉您有关您编写的代码的信息:它们有时会告诉您关于编译器认为您可能打算编写的代码。
然后为该参数使用不同的名称 "hey, yeah, I know"。
这也将使代码更加清晰,意图得到充分记录。
是的,非捕获变量可以被 lambda 参数隐藏。
在 OP 中 lambda 的特殊情况下,您可能会争辩说 value
的内部声明不会影响外部声明的范围,因为 lambda 没有捕获。尽管如此,可以在 lambda 主体内部看到外部 value
,因为 lambda 主体仍在封闭块的范围内:
(C++14 §5.1.2/p.7): The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator, but for purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming idexpressions referring to non-static class members into class member access expressions using (*this) (9.3.1), the compound-statement is considered in the context of the lambda-expression.
从外部作用域使用非捕获变量的 odr 是错误的,但是没有捕获的 lambda 可以使用在外部作用域中定义的名称,如果它不是 odr-使用(在这种情况下,变量 未 被捕获。)特别是,可以使用来自外部范围的 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
启用正是因为它经常会警告你一些你并不真正关心的事情。
我有一个看起来像这样的代码 - 它被大大简化了,但是这个片段编译并表现出相同的行为:
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 不捕获任何内容,因此在这里应该没问题。
我错过了什么?
您没有注意到编译器并不完美,有时会在相对较新的语言功能没有多大意义的情况下发出愚蠢的警告。
另一方面,警告通常都是为了确保您真的打算编写您编写的代码,而不是其他代码。也许您打算捕获外部 value
但是 — 无论出于何种原因:也许您没有注意 — 未能捕获它并重新声明它。
在这段代码中,这看起来确实有点牵强,但重点是警告并不总是告诉您有关您编写的代码的信息:它们有时会告诉您关于编译器认为您可能打算编写的代码。
然后为该参数使用不同的名称 "hey, yeah, I know"。
这也将使代码更加清晰,意图得到充分记录。
是的,非捕获变量可以被 lambda 参数隐藏。
在 OP 中 lambda 的特殊情况下,您可能会争辩说 value
的内部声明不会影响外部声明的范围,因为 lambda 没有捕获。尽管如此,可以在 lambda 主体内部看到外部 value
,因为 lambda 主体仍在封闭块的范围内:
(C++14 §5.1.2/p.7): The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator, but for purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming idexpressions referring to non-static class members into class member access expressions using (*this) (9.3.1), the compound-statement is considered in the context of the lambda-expression.
从外部作用域使用非捕获变量的 odr 是错误的,但是没有捕获的 lambda 可以使用在外部作用域中定义的名称,如果它不是 odr-使用(在这种情况下,变量 未 被捕获。)特别是,可以使用来自外部范围的 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
启用正是因为它经常会警告你一些你并不真正关心的事情。