繁体   English   中英

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

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

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

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.

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

capture:
    identifier
    & identifier
    this

您可以看到, &this在语法上是不允许的。 这是不允许的原因是因为你绝不会想捕捉this引用,因为它是一个小的常量指针。 你永远只能希望按值传递它-所以语言只是不支持拍摄this作为参考。

要明确捕获this内容,可以使用[this]作为lambda-introducer

第一次capture可以是capture-default ,即:

capture-default:
    &
    =

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

5.1.2.7/8:

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

所以拉姆达行为,如果它是包围部件功能的一部分(在你的例子一样使用名称的使用,当成员名称x ),所以它会产生的“隐性习惯” this就像一个成员函数一样。

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

因此,您可以将[this][&][=][&,this]用作lambda-introducer以按值捕获this指针。

但是[&this][=, this]格式错误。 在最后一种情况下,gcc宽容地警告[=,this]explicit by-copy capture of 'this' redundant with by-copy capture default而不是错误。

由于标准在“捕获”列表中没有&this

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有效,而&this无效。 同样,捕获this意味着通过引用捕获*this (这是一个左值,即对象本身), 而不是 通过value捕获this指针!

我不确定我是否正确理解了这个问题,所以我的回答在问题的上下文中不合适。

如果要修改 lambda 中 class 中的值,则可以:

class C {
public:
    void foo() {
        C* this_ptr_2 = this;
        auto f = [&this_ptr_2]{
            this_ptr_2->x = 69; // Modify a class member.
        };
        f();
    }

private:
    int x;
};

同样,我不知道这是否回答了您的问题。 但是,如果您的意思是要修改 lambda 中的 class 成员。 我想以上应该足够了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM