这个带有空捕获列表的 lambda 如何能够引用到达范围名称?
how is this lambda with an empty capture list able to refer to reaching-scope name?
在 C++14 标准 § 5.1.2/12 中,它显示了一个 lambda 表达式的示例,该表达式显然似乎能够引用到达范围的变量 x
,即使:
- 捕获列表为空,即没有捕获默认值
- 评论说"does not capture
x
"
示例如下:
void f(int, const int (&)[2] = {}) { } // #1
void test() {
const int x = 17;
auto g = [](auto a) {
f(x); // OK: calls #1, does not capture x
};
}
看到它 does compile。它似乎取决于 x
是 const
;如果 const
被删除,它就不再像人们预期的那样编译(捕获列表为空)。即使我将参数设置为 int
以使其不再是通用的 lambda,也会发生这种情况。
即使捕获列表为空,lambda 怎么可能引用 x
?这怎么可能同时显然 not 捕获 x
(如评论所述)?
我在这个主题上发现的最接近的东西是其他人在评论中切线这个。
这是标准中的完整部分 5.1.2/12:
A lambda-expression with an associated capture-default that does not explicitly capture this
or a variable with automatic storage duration (this excludes any id-expression that has been found to refer to an init-capture’s associated non-static data member), is said to implicitly capture the entity (i.e., this
or a variable) if the compound-statement:
- odr-uses (3.2) the entity, or
- names the entity in a potentially-evaluated expression (3.2) where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.
[ Example:
void f(int, const int (&)[2] = {}) { } // #1
void f(const int&, const int (&)[1]) { } // #2
void test() {
const int x = 17;
auto g = [](auto a) {
f(x); // OK: calls #1, does not capture x
};
auto g2 = [=](auto a) {
int selector[sizeof(a) == 1 ? 1 : 2]{};
f(x, selector); // OK: is a dependent expression, so captures x
};
}
—end example ] All such implicitly captured entities shall be declared within the reaching scope of the lambda expression. [ Note: The implicit capture of an entity by a nested lambda-expression can cause its implicit capture by the containing lambda-expression (see below). Implicit odr-uses of this can result in implicit capture. —end note ]
您的报价正确。如果变量odr-used,则需要捕获该变量。 ODR-use 基本上意味着该变量在需要定义的上下文中使用。因此,要么获取其地址,要么获取对它的引用,等等。一个关键的例外是,来自 [basic.def.odr]:
A variable x
whose name appears as a potentially-evaluated expression ex
is odr-used by ex
unless applying
the lvalue-to-rvalue conversion (4.1) to x
yields a constant expression (5.20) that does not invoke any nontrivial
functions and, if x
is an object, ex
is an element of the set of potential results of an expression e
, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression (Clause
5).
因此,在您的示例中,对 x
应用左值到右值的转换会产生常量表达式(因为 x
是常量积分),因此它未被使用。由于它不是 odr-used,因此不必捕获它。
另一方面,如果 x
绑定到一个引用(例如 f
将其参数作为 const int&
),那么它 会 被 odr 使用,因此必须被捕获。在给出的第二个示例中,x
的 "odr-use-ness" 依赖于 通用 lambda 参数是什么,因此为了理智起见,无论如何都将其视为捕获。
在 C++14 标准 § 5.1.2/12 中,它显示了一个 lambda 表达式的示例,该表达式显然似乎能够引用到达范围的变量 x
,即使:
- 捕获列表为空,即没有捕获默认值
- 评论说"does not capture
x
"
示例如下:
void f(int, const int (&)[2] = {}) { } // #1
void test() {
const int x = 17;
auto g = [](auto a) {
f(x); // OK: calls #1, does not capture x
};
}
看到它 does compile。它似乎取决于 x
是 const
;如果 const
被删除,它就不再像人们预期的那样编译(捕获列表为空)。即使我将参数设置为 int
以使其不再是通用的 lambda,也会发生这种情况。
即使捕获列表为空,lambda 怎么可能引用 x
?这怎么可能同时显然 not 捕获 x
(如评论所述)?
我在这个主题上发现的最接近的东西是其他人在评论中切线
这是标准中的完整部分 5.1.2/12:
A lambda-expression with an associated capture-default that does not explicitly capture
this
or a variable with automatic storage duration (this excludes any id-expression that has been found to refer to an init-capture’s associated non-static data member), is said to implicitly capture the entity (i.e.,this
or a variable) if the compound-statement:
- odr-uses (3.2) the entity, or
- names the entity in a potentially-evaluated expression (3.2) where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.
[ Example:
void f(int, const int (&)[2] = {}) { } // #1 void f(const int&, const int (&)[1]) { } // #2 void test() { const int x = 17; auto g = [](auto a) { f(x); // OK: calls #1, does not capture x }; auto g2 = [=](auto a) { int selector[sizeof(a) == 1 ? 1 : 2]{}; f(x, selector); // OK: is a dependent expression, so captures x }; }
—end example ] All such implicitly captured entities shall be declared within the reaching scope of the lambda expression. [ Note: The implicit capture of an entity by a nested lambda-expression can cause its implicit capture by the containing lambda-expression (see below). Implicit odr-uses of this can result in implicit capture. —end note ]
您的报价正确。如果变量odr-used,则需要捕获该变量。 ODR-use 基本上意味着该变量在需要定义的上下文中使用。因此,要么获取其地址,要么获取对它的引用,等等。一个关键的例外是,来自 [basic.def.odr]:
A variable
x
whose name appears as a potentially-evaluated expressionex
is odr-used byex
unless applying the lvalue-to-rvalue conversion (4.1) tox
yields a constant expression (5.20) that does not invoke any nontrivial functions and, ifx
is an object,ex
is an element of the set of potential results of an expressione
, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression (Clause 5).
因此,在您的示例中,对 x
应用左值到右值的转换会产生常量表达式(因为 x
是常量积分),因此它未被使用。由于它不是 odr-used,因此不必捕获它。
另一方面,如果 x
绑定到一个引用(例如 f
将其参数作为 const int&
),那么它 会 被 odr 使用,因此必须被捕获。在给出的第二个示例中,x
的 "odr-use-ness" 依赖于 通用 lambda 参数是什么,因此为了理智起见,无论如何都将其视为捕获。