这是我能想出的最简单的例子,可以重现问题。
template<class T>
struct X
{
static void foo()
{
static int z = 0;
[]{ z = 1; }();
}
};
int main()
{
X<int>::foo();
return 0;
}
我已经尝试过使用MinGW 4.6和4.7,以及Ubuntu中的g ++ 4.6,所有这些都给了我链接错误“未定义引用`z'”。所以现在这让我想知道这是否合法。 VC10没问题。
如果X是普通类而不是模板,则它有效。另外,我认为它与lambdas无关,因为即使我用本地类替换lambda,我也会收到错误。
答案 0 :(得分:10)
g ++接受以下内容,但VC ++不接受:
[&z]{ z = 1; }();
此处正在捕获z
,因此g ++不会抱怨未定义的引用。但是:
<强> 5.1.2 / 10:强>
使用通常的非限定名称查找规则(3.4.1)查找捕获列表中的标识符;每个这样的查找都应该找到 在到达时声明自动存储持续时间的变量 本地lambda表达式的范围。
z
不自动存储空间。因此无法捕获z
。因此,g ++行为是不正确的,VC ++是正确的。
在您的代码中,VC ++接受而g ++不接受:
[]{ z = 1; }();
VC ++将 z
作为静态存储访问,这在lambda体中是允许的。 g ++显然没有将名称z
解析为上面声明的静态变量,因此抛出未定义的引用,而它不应该。
<强> TL;博士强> 这可能是g ++中的一个错误
修改强> It is indeed a bug并在4.7中修复。
答案 1 :(得分:-1)
我不明白为什么它适用于普通类而不适用于模板。但是,如果通过引用捕获局部变量z
,则可以使示例正常工作:
static void foo()
{
static int z = 0;
[&z]{ z = 1; }(); // Note: [&z]
}
维基百科有更多信息here。