我理解在lambda中捕获this
(修改对象属性)的正确方法如下:
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.
答案 0 :(得分:95)
[&this]
不起作用的原因是因为它是语法错误。 lambda-introducer
中的每个逗号分隔参数均为capture
:
capture:
identifier
& identifier
this
您可以看到语法不允许&this
。它不被允许的原因是因为你永远不想通过引用捕获this
,因为它是一个小的const指针。您只希望按值传递它 - 因此语言不支持通过引用捕获this
。
要明确捕获this
,您可以使用[this]
作为lambda-introducer
。
第一个capture
可以是capture-default
,即:
capture-default:
&
=
这意味着分别通过引用(&
)或值(=
)自动捕获我使用的任何内容 - 但是this
的处理是特殊的 - 在这两种情况下它都被捕获由于前面给出的原因的值(即使默认捕获&
,这通常意味着通过引用捕获)。
5.1.2.7/8:
出于名称查找(3.4)的目的,确定
this
(9.3.2)的类型和值并转换id- 使用(*this)
(9.3.1)将非静态类成员引用到类成员访问表达式中的表达式, 复合语句[OF THE LAMBDA]在lambda表达的上下文中被考虑。
因此,当使用成员名称时,lambda就好像它是封闭成员函数的一部分一样(比如在你的例子中使用名称x
),因此它将生成{{1的“隐式用法”就像成员函数一样。
如果lambda-capture包含捕获默认值
this
,则lambda-capture中的标识符不应为 前面是&
。如果lambda-capture包含捕获默认值&
,则lambda-capture不应包含=
及其包含的每个标识符都应以this
开头。标识符或&
不得超过 一次在lambda-capture中。
因此,您可以使用this
,[this]
,[&]
或[=]
作为[&,this]
来按值捕获lambda-introducer
指针。< / p>
但this
和[&this]
格式不正确。在最后一种情况下,gcc宽容地警告[=, this]
[=,this]
而不是错误。
答案 1 :(得分:3)
因为标准在“捕获”列表中没有&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
指针按值!