这个带有空捕获列表的 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,即使:

  1. 捕获列表为空,即没有捕获默认值
  2. 评论说"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。它似乎取决于 xconst;如果 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 参数是什么,因此为了理智起见,无论如何都将其视为捕获。