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