这个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
,即使:
In the C++14 standard § 5.1.2/12 it shows an example of a lambda expression that apparently seems to be able to refer to a reaching scope's variable x
, even though:
- 捕获列表为空,即没有捕获默认值
- 评论说它不捕获
x
- the capture list is empty, i.e. no capture-default
- the comment says that it "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
};
}
查看它编译。它似乎取决于 x
是 const
;如果 const
被删除,它不再编译的原因预期(捕获列表为空)。即使我使参数 int
,这样它不再是一个通用的lambda。
See that it does compile. It seems to hinge on x
being const
; if the const
is removed, it no longer compiles for the reasons one would expect (capture list is empty). It happens even if I make the parameter be int
so that it's no longer a generic lambda.
尽管捕获列表是空的,lambda可能指向 x
吗?这是怎么可能的,同时显然不是捕获 x
(如评论所说)?
How is it possible for the lambda to refer to x
even though the capture list is empty? And how is this possible while at the same time apparently not capturing x
(as the comment says)?
我在这个问题上发现的最近的东西是别人切向的在注释中注意到这一点。
The closest thing I found on this subject was someone else tangentially noticing this in a comment.
这是标准的全部5.1.2 / 12部分:
Here's the full section 5.1.2/12 from the standard:
使用关联的捕获默认值的
表达式未明确捕获 或具有自动存储持续时间的变量(这排除了发现引用 init-capture 的关联非主体的 id-expression 静态数据成员),被称为隐含地捕获实体(即,
this
或一个变量) / em>:
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使用(3.2)实体,或
- 在潜在求值的表达式(3.2)中,其中包围的full-expression取决于在lambda表达式的到达范围内声明的通用lambda参数。
- 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.
[示例:
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 应在lambda表达式的到达范围内声明。 [注意:嵌套的 lambda表达式对实体的隐式捕获可以通过包含 lambda-expression )。隐式odr使用这可能导致隐式捕获。 - 结束注释]
—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使用基本上意味着变量在需要定义的上下文中使用。因此,它的地址被采取,或引用它,等等。一个关键的例外是,从[basic.def.odr]:
You have the right quote. A variable needs to be captured if it is odr-used. ODR-use means basically that the variable is used in a context where it needs a definition. So either its address is taken, or a reference is taken to it, etc. One key exception is, from [basic.def.odr]:
变量
x
的名称显示为可能计算的表达式ex
为 odr-used 由ex
除非应用
左值到右值转换(4.1)到x
产生一个常数表达式(5.20),它不会调用任何重要的
函数,如果x
是一个对象,ex
是表达式e
的潜在结果集合的元素,其中应用了左值到右值转换(4.1) to e或e是一个废值表达式(条款
5)。
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 -用过的。因为它不是odr使用,它不必被捕获。
So in your example, applying lvalue-to-rvalue conversion on x
yields a constant expression (since x
is a constant integral), so it's not odr-used. Since it's not odr-used, it doesn't have to be captured.
另一方面,如果 x
绑定到一个引用(例如 f
将其参数作为 const int&
), 被使用,因此必须被捕获。在给出的第二个示例中, x
的odr-use-ness是依赖于关于通用lambda参数是什么,捕获反正为了理智的缘故。
On the other hand, if x
were bound to a reference (e.g. f
took its argument as const int&
), then it would be odr-used, and so would have to be captured. In the second example presented, x
's "odr-use-ness" is dependent on what the generic lambda argument is, so that is considered captured anyway for sanity's sake.
这篇关于这个lambda与一个空的捕获列表如何能够引用到达范围名称?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!