I understand the correct way to capture this
(to modify object properties) in a lambda is as follows:
我理解在lambda中捕获(修改对象属性)的正确方式如下:
auto f = [this] () { /* ... */ };
But I'm curious as to the following peculiarity I've seen:
但我很好奇,我看到了以下的特点:
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;
};
The oddity that I am confused by (and would like answered) is why the following works:
我感到困惑(也想回答)的奇怪之处在于,为什么会有以下的作品:
auto f = [&] () { /* ... */ }; // capture everything by reference
And why I cannot explicitly capture this
by reference:
以及为什么我不能通过引用来明确地说明这一点:
auto f = [&this] () { /* ... */ }; // a compiler error as seen above.
2 个解决方案
#1
74
The reason [&this]
doesn't work is because it is a syntax error. Each comma-seperated parameter in the lambda-introducer
is a capture
:
它之所以不起作用是因为它是一个语法错误。lambda导入器中的每个逗号分隔参数都是一个捕获:
capture:
identifier
& identifier
this
You can see that &this
isn't allowed syntactically. The reason it isn't allowed is because you would never want to capture this
by reference, as it is a small const pointer. You would only ever want to pass it by value - so the language just doesn't support capturing this
by reference.
你可以看到这在语法上是不允许的。不允许这样做的原因是您永远不会希望通过引用捕获它,因为它是一个小的const指针。您只希望通过值传递它——因此语言不支持通过引用捕获它。
To capture this
explicitly you can use [this]
as the lambda-introducer
.
要显式地捕获它,您可以使用[this]作为lambda导入器。
The first capture
can be a capture-default
which is:
第一个捕获可以是捕获-默认值,即:
capture-default:
&
=
This means capture automatically whatever I use, by reference (&
) or by value (=
) respectively - however the treatment of this
is special - in both cases it is captured by value for the reasons given previously (even with a default capture of &
, which usually means capture by reference).
这意味着自动捕获我使用的任何东西,分别通过引用(&)或值(=)—但是处理方法是特殊的—在这两种情况下,它都是由于前面给出的原因被值捕获的(即使默认捕获&,通常意味着通过引用捕获)。
5.1.2.7/8:
5.1.2.7/8:
For purposes of name lookup (3.4), determining the type and value of
this
(9.3.2) and transforming id- expressions referring to non-static class members into class member access expressions using(*this)
(9.3.1), the compound-statement [OF THE LAMBDA] is considered in the context of the lambda-expression.为了便于名称查找(3.4),确定这个(9.3.2)的类型和值(9.3.2),并将非静态类成员的id表达式转换为使用(*this)(9.3.1)的类成员访问表达式,在LAMBDA表达式的上下文中考虑[LAMBDA]的复合语句。
So the lambda acts as if it is part of the enclosing member function when using member names (like in your example the use of the name x
), so it will generate "implicit usages" of this
just like a member function does.
因此,lambda在使用成员名(比如在示例中使用名称x)时,就好像它是封闭成员函数的一部分一样,因此它将生成这个函数的“隐式用法”,就像使用成员函数一样。
If a lambda-capture includes a capture-default that is
&
, the identifiers in the lambda-capture shall not be preceded by&
. If a lambda-capture includes a capture-default that is=
, the lambda-capture shall not containthis
and each identifier it contains shall be preceded by&
. An identifier orthis
shall not appear more than once in a lambda-capture.如果一个lambda-capture包含一个-default(即&),那么这个lambda-capture中的标识符不应该在&之前。如果一个lambda-capture包含一个-default(=),那么这个lambda-capture不应该包含这个参数,并且它包含的每个标识符前面应该包含&。标识符或该标识符不能在lambda-捕获中出现不止一次。
So you can use [this]
, [&]
, [=]
or [&,this]
as a lambda-introducer
to capture the this
pointer by value.
因此,您可以使用[&]、[=]或[&,这]作为一个lambda-介绍人来捕获该指针的值。
However [&this]
and [=, this]
are ill-formed. In the last case gcc forgivingly warns for [=,this]
that explicit by-copy capture of ‘this’ redundant with by-copy capture default
rather than errors.
然而,[&this]和[=,this]是不良的形式。在最后一种情况下,gcc宽容地警告[=,this]显式的“this”的副拷贝捕获与副拷贝捕获的默认值而不是错误。
#2
1
Because standard doesn't have &this
in Captures lists:
因为标准没有,这在捕获列表中:
N4713 8.4.5.2 Captures:
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
For the purposes of lambda capture, an expression potentially references local entities as follows:
出于lambda捕获的目的,表达式可能引用本地实体如下:
7.3 A this expression potentially references *this.
7.3 A这个表达式可能引用*this。
So, standard guarantees this
and *this
is valid, and &this
is invalid. Also, capturing this
means capturing *this
(which is a lvalue, the object itself) by reference, rather than capturing this
pointer by value!
因此,标准保证这个和*这个是有效的,并且这个是无效的。另外,捕获这意味着通过引用捕获*this(它是一个lvalue,对象本身),而不是通过值捕获这个指针!
#1
74
The reason [&this]
doesn't work is because it is a syntax error. Each comma-seperated parameter in the lambda-introducer
is a capture
:
它之所以不起作用是因为它是一个语法错误。lambda导入器中的每个逗号分隔参数都是一个捕获:
capture:
identifier
& identifier
this
You can see that &this
isn't allowed syntactically. The reason it isn't allowed is because you would never want to capture this
by reference, as it is a small const pointer. You would only ever want to pass it by value - so the language just doesn't support capturing this
by reference.
你可以看到这在语法上是不允许的。不允许这样做的原因是您永远不会希望通过引用捕获它,因为它是一个小的const指针。您只希望通过值传递它——因此语言不支持通过引用捕获它。
To capture this
explicitly you can use [this]
as the lambda-introducer
.
要显式地捕获它,您可以使用[this]作为lambda导入器。
The first capture
can be a capture-default
which is:
第一个捕获可以是捕获-默认值,即:
capture-default:
&
=
This means capture automatically whatever I use, by reference (&
) or by value (=
) respectively - however the treatment of this
is special - in both cases it is captured by value for the reasons given previously (even with a default capture of &
, which usually means capture by reference).
这意味着自动捕获我使用的任何东西,分别通过引用(&)或值(=)—但是处理方法是特殊的—在这两种情况下,它都是由于前面给出的原因被值捕获的(即使默认捕获&,通常意味着通过引用捕获)。
5.1.2.7/8:
5.1.2.7/8:
For purposes of name lookup (3.4), determining the type and value of
this
(9.3.2) and transforming id- expressions referring to non-static class members into class member access expressions using(*this)
(9.3.1), the compound-statement [OF THE LAMBDA] is considered in the context of the lambda-expression.为了便于名称查找(3.4),确定这个(9.3.2)的类型和值(9.3.2),并将非静态类成员的id表达式转换为使用(*this)(9.3.1)的类成员访问表达式,在LAMBDA表达式的上下文中考虑[LAMBDA]的复合语句。
So the lambda acts as if it is part of the enclosing member function when using member names (like in your example the use of the name x
), so it will generate "implicit usages" of this
just like a member function does.
因此,lambda在使用成员名(比如在示例中使用名称x)时,就好像它是封闭成员函数的一部分一样,因此它将生成这个函数的“隐式用法”,就像使用成员函数一样。
If a lambda-capture includes a capture-default that is
&
, the identifiers in the lambda-capture shall not be preceded by&
. If a lambda-capture includes a capture-default that is=
, the lambda-capture shall not containthis
and each identifier it contains shall be preceded by&
. An identifier orthis
shall not appear more than once in a lambda-capture.如果一个lambda-capture包含一个-default(即&),那么这个lambda-capture中的标识符不应该在&之前。如果一个lambda-capture包含一个-default(=),那么这个lambda-capture不应该包含这个参数,并且它包含的每个标识符前面应该包含&。标识符或该标识符不能在lambda-捕获中出现不止一次。
So you can use [this]
, [&]
, [=]
or [&,this]
as a lambda-introducer
to capture the this
pointer by value.
因此,您可以使用[&]、[=]或[&,这]作为一个lambda-介绍人来捕获该指针的值。
However [&this]
and [=, this]
are ill-formed. In the last case gcc forgivingly warns for [=,this]
that explicit by-copy capture of ‘this’ redundant with by-copy capture default
rather than errors.
然而,[&this]和[=,this]是不良的形式。在最后一种情况下,gcc宽容地警告[=,this]显式的“this”的副拷贝捕获与副拷贝捕获的默认值而不是错误。
#2
1
Because standard doesn't have &this
in Captures lists:
因为标准没有,这在捕获列表中:
N4713 8.4.5.2 Captures:
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
For the purposes of lambda capture, an expression potentially references local entities as follows:
出于lambda捕获的目的,表达式可能引用本地实体如下:
7.3 A this expression potentially references *this.
7.3 A这个表达式可能引用*this。
So, standard guarantees this
and *this
is valid, and &this
is invalid. Also, capturing this
means capturing *this
(which is a lvalue, the object itself) by reference, rather than capturing this
pointer by value!
因此,标准保证这个和*这个是有效的,并且这个是无效的。另外,捕获这意味着通过引用捕获*this(它是一个lvalue,对象本身),而不是通过值捕获这个指针!