C++ 为什么我不能在 lambda 中捕获这个按引用('&this')?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16323032/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:15:43  来源:igfitidea点击:

Why can't I capture this by-reference ('&this') in lambda?

c++c++11lambda

提问by Anthony Sottile

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

我理解this在 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 thisby reference:

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

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

回答by Andrew Tomazos

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

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

capture:
    identifier
    & identifier
    this

You can see that &thisisn't allowed syntactically. The reason it isn't allowed is because you would never want to capture thisby 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 thisby reference.

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

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

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

The first capturecan be a capture-defaultwhich is:

第一个capture可以是一个capture-default

capture-default:
    &
    =

This means capture automatically whatever I use, by reference (&) or by value (=) respectively - however the treatment of thisis 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).

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

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)、确定this(9.3.2)的类型和值以及使用(*this)(9.3.1) 将引用非静态类成员的 id 表达式转换为类成员访问表达式的目的,复合语句 [OF THE 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 thisjust like a member function does.

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

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 thisand each identifier it contains shall be preceded by &. An identifier or thisshall not appear more than once in a lambda-capture.

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

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

所以,你可以使用[this][&][=][&,this]作为lambda-introducer捕获this的价值指针。

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 defaultrather than errors.

然而,[&this][=, this]是畸形的。在最后一种情况GCC forgivingly警告的[=,this]那个explicit by-copy capture of ‘this' redundant with by-copy capture default,而不是错误。

回答by u6949852

Because standard doesn't have &thisin Captures lists:

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

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:

    7.3 A this expression potentially references *this.

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

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

So, standard guarantees thisand *thisis valid, and &thisis invalid. Also, capturing thismeans capturing *this(which is a lvalue, the object itself) by reference, rather thancapturing thispointer by value!

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