[英]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.