[英]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
出於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.