【问题标题】:Using of not captured variable in lambda在 lambda 中使用未捕获的变量
【发布时间】:2016-08-03 18:07:01
【问题描述】:

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

具有关联捕获默认值的 lambda 表达式未显式捕获此变量或具有自动存储持续时间的变量(这不包括已发现引用 initcapture 关联的非静态数据成员的任何 id 表达式),据说如果复合语句隐式捕获实体(即 this 或变量):

  • 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 表达式隐式捕获(见下文)。对 this 的隐式 odr 使用可能会导致隐式捕获。 ——尾注]

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

--

upd:感谢大家解释它是如何工作的。稍后我将尝试查找并发布有关此案例的标准参考。

【问题讨论】:

  • x 是一个常量表达式。由于引用,ODR 仅用于#2。
  • 换句话说,g 的行为就好像它的主体是 { f(17); }。

标签: c++ lambda standards c++14


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-28
    • 1970-01-01
    • 2013-11-26
    • 2011-11-05
    相关资源
    最近更新 更多