98

我了解this在 lambda 中捕获(修改对象属性)的正确方法如下:

auto f = [this] () { /* ... */ };

但我很好奇我见过的以下特点:

class C {
    public:
        void foo() {
            // auto f = [] () { // this not captured
            auto f = [&] () { // why does this work?
            // auto f = [&this] () { // Expected ',' before 'this'
            // auto f = [this] () { // works as expected
                x = 5;
            };
            f();
        }

    private:
        int x;
};

我感到困惑(并且想回答)的奇怪之处是以下工作的原因:

auto f = [&] () { /* ... */ }; // capture everything by reference

以及为什么我不能通过this引用显式捕获:

auto f = [&this] () { /* ... */ }; // a compiler error as seen above.
4

2 回答 2

118

原因[&this]不起作用是因为它是语法错误。中的每个逗号分隔的参数lambda-introducer都是capture

capture:
    identifier
    & identifier
    this

您可以看到在&this语法上是不允许的。不允许它的原因是因为您永远不想this通过引用捕获,因为它是一个小的 const 指针。您只想按值传递它 - 因此该语言不支持this通过引用捕获。

要明确捕获this,您可以将[this]其用作lambda-introducer.

第一个capture可以capture-default是:

capture-default:
    &
    =

这意味着自动捕获我使用的任何内容,分别通过引用(&)或值(=)-但是处理this是特殊的-在这两种情况下,由于前面给出的原因,它都是按值捕获的(即使默认捕获&,这通常意味着通过引用捕获)。

5.1.2.7/8:

出于名称查找 (3.4) 的目的,确定this(9.3.2) 的类型和值并使用 (9.3.1) 将引用非静态类成员的 id- 表达式转换为类成员访问表达式(*this),复合语句 [OF THE LAMBDA] 在 lambda 表达式的上下文中被考虑。

因此,lambda 在使用成员名称时就好像它是封闭成员函数的一部分(就像在您的示例中使用 name 一样x),因此它将this像成员函数一样生成“隐式用法”。

如果 lambda-capture 包含一个 capture-default 即&,则 lambda-capture 中的标识符不应以&. 如果 lambda-capture 包含一个 capture-default 即=,则 lambda-capture 不应包含 this,并且它包含的每个标识符都应以 开头&。一个标识符 orthis不得在 lambda-capture 中出现多次。

因此,您可以使用[this],或as a按值捕获指针。[&][=][&,this]lambda-introducerthis

但是[&this][=, this]格式不正确。在最后一种情况下,gcc 会对此发出警告[=,this]explicit by-copy capture of ‘this’ redundant with by-copy capture default不是错误。

于 2013-05-01T17:24:22.107 回答
7

&this因为标准在 Captures 列表中没有:

N4713 8.4.5.2 捕获:

lambda-capture:
    capture-default
    capture-list
    capture-default, capture-list

capture-default:
    &
    =
capture-list:
    capture...opt
    capture-list, capture...opt
capture:
    simple-capture
    init-capture
simple-capture:
    identifier
    &identifier
    this
    * this
init-capture:
    identifier initializer
    &identifier initializer
  1. 出于 lambda 捕获的目的,表达式可能会引用本地实体,如下所示:

    7.3 this 表达式可能引用 *this。

所以,标准保证有效,this无效。此外,捕获意味着通过引用捕获(这是一个左值,对象本身),而不是按值捕获指针!*this&thisthis*thisthis

于 2017-12-06T16:00:51.853 回答