简体   繁体   English

C ++ 11 lambda可以捕获文件范围变量吗?

[英]Can a C++11 lambda capture a file scope variable?

Section 5.1.2 p10 of the ISO C++11 specification states: ISO C ++ 11规范的5.1.2 p10部分规定:

The identifiers in a capture-list are looked up using the usual rules for unqualified name lookup (3.4.1); 使用用于不合格名称查找的常规规则在捕获列表中查找标识符(3.4.1); each such lookup shall find a variable with automatic storage duration declared in the reaching scope of the local lambda expression. 每个这样的查找都将找到一个在本地lambda表达式的作用域内声明的具有自动存储持续时间的变量。 An entity (ie a variable or this) is said to be explicitly captured if it appears in the lambda-expression's capture-list. 如果某个实体(即变量或此变量)出现在lambda表达式的捕获列表中,则称该实体已被明确捕获。

This seems to imply that a lambda cannot capture a file scope variable. 这似乎暗示着lambda无法捕获文件范围变量。 For example, this program should be illegal: 例如,该程序应该是非法的:

#include <iostream>

int x = 13;

int main()
{
  auto l = [](){ return x; };

  std::cout << l() << std::endl;

  return 0;
}

However, g++ 4.7.1 produces the result I expect: 但是, g++ 4.7.1产生了我期望的结果:

$ g++ --version
g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ -std=c++11 lambda.cpp 
$ ./a.out 
13

But clang 3.0 crashes: 但是clang 3.0崩溃了:

$ clang --version
Ubuntu clang version 3.0-6ubuntu3 (tags/RELEASE_30/final) (based on LLVM 3.0)
Target: i386-pc-linux-gnu
Thread model: posix
$ clang -std=c++11 lambda.cpp 
0  libLLVM-3.0.so.1 0xb70a59e8
1  libLLVM-3.0.so.1 0xb70a5f34
2                   0xb775d400 __kernel_sigreturn + 0
3  clang            0x0869f2e9 clang::Sema::DeduceAutoType(clang::TypeSourceInfo*, clang::Expr*, clang::TypeSourceInfo*&) + 73
<snip>

Is my program illegal or not? 我的程序是否非法? If it is illegal, what is the rationale for the proscription on capturing file scope variables? 如果这是非法的,那么在获取文件范围变量时进行禁令的理由是什么?

For purposes of name lookup, the body of the lambda is considered to be in the context of the lambda expression. 出于名称查找的目的,lambda的主体被视为在lambda表达式的上下文中。 That is, name lookup happens as if you used the name outside the lambda. 也就是说,名称查找的过程就像您在lambda之外使用名称一样。 See [expr.prim.lambda]/7. 参见[expr.prim.lambda] / 7。 For example: 例如:

#include <iostream>

int x = 13;
int y = 0;

int main()
{
  static int y = 42;
  int z = 1729;

  auto l = [/*forget about the capture for a moment*/]()
  { return x+y+z; };
  // find the names x,y,z as if they had been mentioned outside the lambda
  // find the locals y, z and the global x

  std::cout << l() << std::endl;

  return 0;
}

Now, you need to capture variables of automatic storage duration. 现在,您需要捕获自动存储持续时间的变量。 I guess this makes it a bit less error-prone, as you can copy and return lambdas, so that the automatic variables have been destroyed when the lambda is called: 我猜这使它更不容易出错,因为您可以复制并返回lambda,因此在调用lambda时自动变量已被破坏:

int main()
{
  static int y = 42;

  std::function<int()> f;
  {
    int z = 1729;

    f = [](){ return x+y+z; }; // imagine we could do this
  }

  std::cout << f() << std::endl; // uh-oh!

  return 0;
}

Of course, this problem does not appear for variables with static storage duration. 当然,对于具有静态存储持续时间的变量,不会出现此问题。

Specifically, [expr.prim.lambda]/12 says: 具体来说,[expr.prim.lambda] / 12说:

If a lambda-expression or an instantiation of the function call operator template of a generic lambda odr-uses (3.2) this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression . 如果通用lambda odr-use的lambda-expression或函数调用操作符模板的实例(3.2)使用this变量或具有自动存储持续时间的变量(从其到达范围开始),则该实体应由lambda-expression捕获。

Non-automatic variables will be found by name lookup as well, but are not affected by this rule. 非自动变量也可以通过名称查找找到,但不受此规则影响。 You can use them without capturing. 您可以使用它们而无需捕获。


NB the odr-use relaxation allows some uses of automatic variables w/o capturing them, such as: 注意: odd-use放宽允许不使用自动变量的某些使用,例如:

int main()
{
  int x = 42;
  constexpr int y = 1789;

  auto l = []() -> int
  {
      decltype(x) my_var = 100;  // no odr-use of `x`
      return my_var*y;           // no odr-use of `y`
  };

  std::cout << l() << std::endl;

  return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM