Entiendo que la forma correcta de capturar this
(modificar las propiedades del objeto) en una lambda es la siguiente:
auto f = [this] () { /* ... */ };
Pero tengo curiosidad por la siguiente peculiaridad que he visto:
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;
};
La rareza que me confunde (y me gustaría recibir una respuesta) es por qué funciona lo siguiente:
auto f = [&] () { /* ... */ }; // capture everything by reference
Y por qué no puedo capturar explícitamente this
por referencia:
auto f = [&this] () { /* ... */ }; // a compiler error as seen above.
this
no se puede cambiar, no es lo suficientemente grande para hacer una referencia más rápido ... y de todos modos , en realidad no existe , por lo que ha ninguna vida real, lo que significa que cualquier referencia a ella estaría pendiente por definición.this
es un valor pr, no un valor l.Respuestas:
La razón
[&this]
no funciona es porque es un error de sintaxis. Cada parámetro separado por comas en ellambda-introducer
es uncapture
:capture: identifier & identifier this
Puede ver que eso
&this
no está permitido sintácticamente. La razón por la que no está permitido es porque nunca querría capturarthis
por referencia, ya que es un pequeño puntero constante. Solo querrá pasarlo por valor, por lo que el lenguaje simplemente no admite la capturathis
por referencia.Para capturar
this
explícitamente, puede usar[this]
comolambda-introducer
.El primero
capture
puede ser uncapture-default
que es:capture-default: & =
Esto significa capturar automáticamente todo lo que uso, por referencia (
&
) o por valor (=
) respectivamente, sin embargo, el tratamiento dethis
es especial, en ambos casos se captura por valor por las razones dadas anteriormente (incluso con una captura predeterminada de&
, que generalmente significa capturar por referencia).5.1.2.7/8:
Entonces, lambda actúa como si fuera parte de la función miembro adjunta cuando se usan nombres de miembros (como en su ejemplo, el uso del nombre
x
), por lo que generará "usos implícitos" de lathis
misma manera que lo hace una función miembro.Así que usted puede utilizar
[this]
,[&]
,[=]
o[&,this]
comolambda-introducer
para capturar elthis
puntero por valor.Sin embargo
[&this]
y[=, this]
están mal formados. En el último caso, gcc advierte con perdón por[=,this]
eso enexplicit by-copy capture of ‘this’ redundant with by-copy capture default
lugar de errores.fuente
[&]
si está haciendo algo como crear un bloque para pasarlo a una estructura de control", pero capture explícitamente si está produciendo una lambda que se usará para propósitos menos simples.[&]
es una idea horrible si el lambda va a sobrevivir al alcance actual. Sin embargo, muchos usos de lambdas son solo formas de pasar bloques a estructuras de control, y el bloque no sobrevivirá al bloque que se creó en el alcance.this
es una palabra clave,this
no es un identificador.Porque estándar no tiene
&this
en las listas de Capturas:N4713 8.4.5.2 Capturas:
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
Entonces, estándar garantiza
this
y*this
es válido y&this
no es válido. Además, capturarthis
significa capturar*this
(que es un valor, el objeto en sí) por referencia , en lugar de capturar elthis
puntero por valor .fuente
*this
captura el objeto por valor