理解C++;0x lambda捕获

理解C++;0x lambda捕获,lambda,c++11,Lambda,C++11,在最近的一个C++0x草案(n3225.pdf)中,我们可以找到5.1.2/10: 使用非限定名称查找的常规规则(3.4.1)查找捕获列表中的标识符;每次这样的查找都应找到一个在本地lambda表达式的到达范围内声明了自动存储持续时间的变量。如果实体(即变量或此)出现在lambda表达式的捕获列表中,则称其为显式捕获 这对我来说似乎有点限制。例如,在我看来,以下事情是不允许的: int global; struct s { int x; void memfun() {

在最近的一个C++0x草案(n3225.pdf)中,我们可以找到5.1.2/10:

使用非限定名称查找的常规规则(3.4.1)查找捕获列表中的标识符;每次这样的查找都应找到一个在本地lambda表达式的到达范围内声明了自动存储持续时间的变量。如果实体(即变量或此)出现在lambda表达式的捕获列表中,则称其为显式捕获

这对我来说似乎有点限制。例如,在我看来,以下事情是不允许的:

int global;

struct s {
    int x;
    void memfun() {
        [x,global]{};
    }
};
因为
x
不一定是具有自动存储功能的变量,
也不一定是全局变量。请注意,此capture子句的目的是让lambda对象存储
x
global
的副本,如果在稍后阶段更改它们,这可能是可取的。我已经知道另一种选择:

int global;

struct s {
    int x;
    void memfun() {
        int copyx = x;
        int copyglobal = global;
        [copyx,copyglobal]{};
    }
};
但这归结为额外的副本和额外的锅炉板,只是为了将
x
global
捕获为副本

此外,我在最新的草案中找不到任何关于在捕获条款中命名本地引用会发生什么的结论:

int main() {
    int  i = 0;
    int &r = i;
    assert([r]{return &r;}() != &i);
}
lambda对象是“复制引用”还是“复制整型”?如果它通过副本捕获引用的对象,这可以为我们节省以前工作中的额外副本

GCC显然支持所有这些示例,并在最后一种情况下存储一个int的副本(这是可取的,IMHO)。但我想知道,根据C++0x草案,这实际上是预期的行为,还是仅仅是一个编译器扩展(分别是一个实现错误)

编辑:

templatetypedef指出了5.1.2/14,它解释了在捕获子句中命名引用时会发生什么。据我所知,这允许我们在第一个示例中使用以下解决方法:

int global;

struct s {
    int x;
    void memfun() {
        auto& cx = x;
        auto& cglob = global;
        [cx,cglob]{};
    }
};
蒂亚,
sellibitze

从您发布的内容来看,您的第一个示例似乎是非法的,因为两个捕获的变量都没有自动持续时间。但是,您可以轻松地修复此问题。要捕获数据成员,您可以只捕获它,而不需要捕获全局成员,因为您可以直接引用它

编辑:正如您所指出的,这不会创建要捕获的值的本地副本。要在创建副本时捕获这些变量,可以捕获这些变量,然后在lambda内部显式创建数据成员的本地副本


关于捕获引用的第二个问题,§5.1.2/14指出,通过副本捕获引用类型的变量将创建引用值的副本,而不是创建引用的副本。因此,lambda将拥有创建引用时引用的值的自己的副本。

在capture子句中命名
x
global
的目的是让lambda对象存储副本。在
::global
s::x
更改其值的情况下,这可能是可取的。因此,不,捕获
这个
不会导致预期的行为。你是对的;我刚刚更新了我的答案。谢谢你指出这一点!感谢您指出5.1.2/14。如果我们对通过复制捕获其他内容感兴趣,我们可以将非自动变量的局部引用作为一种解决方法。在lambda中创建副本与创建lambda时创建副本仍然不同。并不是说这样做很难,只是不能使用您的提案“解决方案”。注意:C++14扩展了可能的捕获子句集