簡體   English   中英

C ++ 11 lambda可以捕獲文件范圍變量嗎?

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

ISO C ++ 11規范的5.1.2 p10部分規定:

使用用於不合格名稱查找的常規規則在捕獲列表中查找標識符(3.4.1); 每個這樣的查找都將找到一個在本地lambda表達式的作用域內聲明的具有自動存儲持續時間的變量。 如果某個實體(即變量或此變量)出現在lambda表達式的捕獲列表中,則稱該實體已被明確捕獲。

這似乎暗示着lambda無法捕獲文件范圍變量。 例如,該程序應該是非法的:

#include <iostream>

int x = 13;

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

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

  return 0;
}

但是, 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

但是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>

我的程序是否非法? 如果這是非法的,那么在獲取文件范圍變量時進行禁令的理由是什么?

出於名稱查找的目的,lambda的主體被視為在lambda表達式的上下文中。 也就是說,名稱查找的過程就像您在lambda之外使用名稱一樣。 參見[expr.prim.lambda] / 7。 例如:

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

現在,您需要捕獲自動存儲持續時間的變量。 我猜這使它更不容易出錯,因為您可以復制並返回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;
}

當然,對於具有靜態存儲持續時間的變量,不會出現此問題。

具體來說,[expr.prim.lambda] / 12說:

如果通用lambda odr-use的lambda-expression或函數調用操作符模板的實例(3.2)使用this變量或具有自動存儲持續時間的變量(從其到達范圍開始),則該實體應由lambda-expression捕獲。

非自動變量也可以通過名稱查找找到,但不受此規則影響。 您可以使用它們而無需捕獲。


注意: 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