簡體   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