在lambda中使用未捕获的变量

Using of not captured variable in lambda

本文关键字:变量 lambda      更新时间:2023-10-16

我不太理解C++14标准草案N4140 5.1.2.12 [expr.prim.lambda]中的一个例子。

如果复合语句

  • odr使用实体,或者
  • 在可能求值的表达式中命名实体,其中封闭的完整表达式依赖于在lambda表达式的到达范围内声明的泛型lambda参数

[示例:

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
  };
}

--结束示例]

所有此类隐式捕获的实体都应在lambda表达式的可达范围内声明。

[注意:嵌套lambda表达式对实体的隐式捕获可能会导致包含lambda表达式(见下文)对其进行隐式捕获。对此的隐式odr使用可能会导致隐式捕获

我认为短语a lambda-expression with an associated capture-default的开头应该禁止任何隐式捕获(并通过注释进行了确认),因此#1调用将导致错误(关于使用未捕获的变量)。那么它是如何工作的呢?f的第一个论点是什么?如果在退出test()作用域后将调用g,该怎么办?如果我将#1签名更改为void(const int&),该怎么办?

--

upd:感谢大家对它工作原理的解释。稍后,我将尝试查找并发布有关此案例的标准参考资料。

正如T.C.在评论中所说,#1不需要捕获,因为x在编译时是已知的,因此被烘焙到lambda中。这与函数f在编译时的已知方式并无不同,因此不需要捕获它。

我相信,如果您将f的签名更改为int const &,您现在正试图传递堆栈上常量的地址,因此可能会发生更改,并且需要通过值或引用捕获x