我正在尝试使用GCC 4.7.2编译以下代码:
#include <iostream>
int foo() {
static int bar;
return [&bar] () { return bar++; } (); // lambda capturing by reference
}
int main (int argc, char* argv[]) {
std::cout << foo() << std::endl;
return 0;
}
似乎进展不顺利,因为输出就是这个:
$p2.cpp: In function ‘int foo()’:
$p2.cpp:6:14: warning: capture of variable ‘bar’ with non-automatic storage duration [enabled by default]
$p2.cpp:4:16: note: ‘int bar’ declared here
所以,我的第一个问题是:
这是GCC的失败,还是代码不合法C ++ 11?这是否已在最新版本的GCC中修复?
我考虑根据这个原则构建一个工件,但是使用非文字静态变量。该工件意味着是shared_ptr&lt;的工厂。 T>对象,当您只需要为同一个实例使用重复的shared_ptr容器时,它可以避免创建新的T对象。
这个工件看起来像:
std::shared_ptr<Foo> create(std::string name) {
static std::unordered_map<std::string,std::weak_ptr<Foo>> registry;
if (auto it = registry.find(name) != registry.end())
return registry[name].lock();
auto b = std::shared_ptr<Foo>(
new Foo(name),
[®istry] (Foo* p) {
registry.erase(p->getName());
delete p;
});
registry.emplace(name,b);
return b;
}
据我所知,如果之前讨论的GCC问题在C ++ 11一致性方面不是问题,那么这个工件也不应该成为问题。使用此hack唯一要注意的是不设置生成的shared_ptr&lt; T>对象可以在静态变量之后被破坏的任何全局对象。
我对此是对的吗?
答案 0 :(得分:79)
为什么你甚至试图捕获bar
?这是静态的。您根本不需要捕获它。只需要捕获自动变量。 Clang会对您的代码产生严重错误,而不仅仅是警告。如果您只是从lambda捕获中删除&bar
,那么代码就能完美运行。
#include <iostream>
int foo() {
static int bar;
return [] () { return bar++; } (); // lambda capturing by reference
}
int main (int argc, char* argv[]) {
std::cout << foo() << std::endl;
std::cout << foo() << std::endl;
std::cout << foo() << std::endl;
return 0;
}
打印
0
1
2
答案 1 :(得分:11)
根据标准,您只能捕获具有自动存储持续时间(或this
的变量,这被称为明确可捕获)。
所以,不,你不能按照标准做到这一点(或者,回答你的第一个问题,这不是有效的C ++ 11而不是编译器错误)
5.1.1 / 2 lambda-capture中的名称应在lambda表达式的上下文中,并且应该是this或指向本地 具有自动存储持续时间的变量或引用。
编辑:而且,正如凯文所说,你甚至不需要捕获本地static
。