为什么我不能用lambda来捕获这个by-reference ('&this') ?

时间:2022-04-18 21:07:42

I understand the correct way to capture this (to modify object properties) in a lambda is as follows:

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

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

But I'm curious as to the following peculiarity I've seen:

但我很好奇,我看到了以下的特点:

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;
};

The oddity that I am confused by (and would like answered) is why the following works:

我感到困惑(也想回答)的奇怪之处在于,为什么会有以下的作品:

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

And why I cannot explicitly capture this by reference:

以及为什么我不能通过引用来明确地说明这一点:

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

2 个解决方案

#1


74  

The reason [&this] doesn't work is because it is a syntax error. Each comma-seperated parameter in the lambda-introducer is a capture:

它之所以不起作用是因为它是一个语法错误。lambda导入器中的每个逗号分隔参数都是一个捕获:

capture:
    identifier
    & identifier
    this

You can see that &this isn't allowed syntactically. The reason it isn't allowed is because you would never want to capture this by reference, as it is a small const pointer. You would only ever want to pass it by value - so the language just doesn't support capturing this by reference.

你可以看到这在语法上是不允许的。不允许这样做的原因是您永远不会希望通过引用捕获它,因为它是一个小的const指针。您只希望通过值传递它——因此语言不支持通过引用捕获它。

To capture this explicitly you can use [this] as the lambda-introducer.

要显式地捕获它,您可以使用[this]作为lambda导入器。

The first capture can be a capture-default which is:

第一个捕获可以是捕获-默认值,即:

capture-default:
    &
    =

This means capture automatically whatever I use, by reference (&) or by value (=) respectively - however the treatment of this is special - in both cases it is captured by value for the reasons given previously (even with a default capture of &, which usually means capture by reference).

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

5.1.2.7/8:

5.1.2.7/8:

For purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming id- expressions referring to non-static class members into class member access expressions using (*this) (9.3.1), the compound-statement [OF THE LAMBDA] is considered in the context of the lambda-expression.

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

So the lambda acts as if it is part of the enclosing member function when using member names (like in your example the use of the name x), so it will generate "implicit usages" of this just like a member function does.

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

If a lambda-capture includes a capture-default that is &, the identifiers in the lambda-capture shall not be preceded by &. If a lambda-capture includes a capture-default that is =, the lambda-capture shall not contain this and each identifier it contains shall be preceded by &. An identifier or this shall not appear more than once in a lambda-capture.

如果一个lambda-capture包含一个-default(即&),那么这个lambda-capture中的标识符不应该在&之前。如果一个lambda-capture包含一个-default(=),那么这个lambda-capture不应该包含这个参数,并且它包含的每个标识符前面应该包含&。标识符或该标识符不能在lambda-捕获中出现不止一次。

So you can use [this], [&], [=] or [&,this] as a lambda-introducer to capture the this pointer by value.

因此,您可以使用[&]、[=]或[&,这]作为一个lambda-介绍人来捕获该指针的值。

However [&this] and [=, this] are ill-formed. In the last case gcc forgivingly warns for [=,this] that explicit by-copy capture of ‘this’ redundant with by-copy capture default rather than errors.

然而,[&this]和[=,this]是不良的形式。在最后一种情况下,gcc宽容地警告[=,this]显式的“this”的副拷贝捕获与副拷贝捕获的默认值而不是错误。

#2


1  

Because standard doesn't have &this in Captures lists:

因为标准没有,这在捕获列表中:

N4713 8.4.5.2 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. For the purposes of lambda capture, an expression potentially references local entities as follows:

    出于lambda捕获的目的,表达式可能引用本地实体如下:

    7.3 A this expression potentially references *this.

    7.3 A这个表达式可能引用*this。

So, standard guarantees this and *this is valid, and &this is invalid. Also, capturing this means capturing *this(which is a lvalue, the object itself) by reference, rather than capturing this pointer by value!

因此,标准保证这个和*这个是有效的,并且这个是无效的。另外,捕获这意味着通过引用捕获*this(它是一个lvalue,对象本身),而不是通过值捕获这个指针!

#1


74  

The reason [&this] doesn't work is because it is a syntax error. Each comma-seperated parameter in the lambda-introducer is a capture:

它之所以不起作用是因为它是一个语法错误。lambda导入器中的每个逗号分隔参数都是一个捕获:

capture:
    identifier
    & identifier
    this

You can see that &this isn't allowed syntactically. The reason it isn't allowed is because you would never want to capture this by reference, as it is a small const pointer. You would only ever want to pass it by value - so the language just doesn't support capturing this by reference.

你可以看到这在语法上是不允许的。不允许这样做的原因是您永远不会希望通过引用捕获它,因为它是一个小的const指针。您只希望通过值传递它——因此语言不支持通过引用捕获它。

To capture this explicitly you can use [this] as the lambda-introducer.

要显式地捕获它,您可以使用[this]作为lambda导入器。

The first capture can be a capture-default which is:

第一个捕获可以是捕获-默认值,即:

capture-default:
    &
    =

This means capture automatically whatever I use, by reference (&) or by value (=) respectively - however the treatment of this is special - in both cases it is captured by value for the reasons given previously (even with a default capture of &, which usually means capture by reference).

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

5.1.2.7/8:

5.1.2.7/8:

For purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming id- expressions referring to non-static class members into class member access expressions using (*this) (9.3.1), the compound-statement [OF THE LAMBDA] is considered in the context of the lambda-expression.

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

So the lambda acts as if it is part of the enclosing member function when using member names (like in your example the use of the name x), so it will generate "implicit usages" of this just like a member function does.

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

If a lambda-capture includes a capture-default that is &, the identifiers in the lambda-capture shall not be preceded by &. If a lambda-capture includes a capture-default that is =, the lambda-capture shall not contain this and each identifier it contains shall be preceded by &. An identifier or this shall not appear more than once in a lambda-capture.

如果一个lambda-capture包含一个-default(即&),那么这个lambda-capture中的标识符不应该在&之前。如果一个lambda-capture包含一个-default(=),那么这个lambda-capture不应该包含这个参数,并且它包含的每个标识符前面应该包含&。标识符或该标识符不能在lambda-捕获中出现不止一次。

So you can use [this], [&], [=] or [&,this] as a lambda-introducer to capture the this pointer by value.

因此,您可以使用[&]、[=]或[&,这]作为一个lambda-介绍人来捕获该指针的值。

However [&this] and [=, this] are ill-formed. In the last case gcc forgivingly warns for [=,this] that explicit by-copy capture of ‘this’ redundant with by-copy capture default rather than errors.

然而,[&this]和[=,this]是不良的形式。在最后一种情况下,gcc宽容地警告[=,this]显式的“this”的副拷贝捕获与副拷贝捕获的默认值而不是错误。

#2


1  

Because standard doesn't have &this in Captures lists:

因为标准没有,这在捕获列表中:

N4713 8.4.5.2 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. For the purposes of lambda capture, an expression potentially references local entities as follows:

    出于lambda捕获的目的,表达式可能引用本地实体如下:

    7.3 A this expression potentially references *this.

    7.3 A这个表达式可能引用*this。

So, standard guarantees this and *this is valid, and &this is invalid. Also, capturing this means capturing *this(which is a lvalue, the object itself) by reference, rather than capturing this pointer by value!

因此,标准保证这个和*这个是有效的,并且这个是无效的。另外,捕获这意味着通过引用捕获*this(它是一个lvalue,对象本身),而不是通过值捕获这个指针!