c++ - examples - Llamar a la función de miembro `this` desde lambda genérico-clang vs gcc
lambda examples c++ (1)
Problema: pasar un lambda genérico (a una función de plantilla) que captura this
y llama a una función miembro de this
sin un explícito this->
does not compile on gcc. Si el lambda no es genérico, o si el lambda no se pasa a ninguna otra función sino que se llama en su lugar, compila con un explícito esto- this->
. Clang es genial con el código en todas las situaciones.
Es hora de otra ronda de clang vs gcc . ¿Quién tiene la razón?
template<typename TF>
void call(TF&& f)
{
f(1);
}
struct Example
{
void foo(int){ }
void bar()
{
call([this](auto x){ foo(x); });
}
};
int main()
{
Example{}.bar();
return 0;
}
- Con
bar()
=call([this](auto x){ foo(x); });
- clang ++ 3.6+ compila .
- g ++ 5.2+ no compila.
error: no se puede llamar a la función miembro ''void Example :: foo (int)'' sin invocar objeto ([this] (auto x) {foo (x);}); `
- Con
bar()
=call([this](auto x){ this->foo(x); });
- clang ++ 3.6+ compila .
- g ++ 5.2+ compila.
- Con
bar()
=call([this](int x){ foo(x); });
- clang ++ 3.6+ compila .
- g ++ 5.2+ compila.
- Con
bar()
=[this](auto x){ foo(x); }(1);
[this](auto x){ foo(x); }(1);
- clang ++ 3.6+ compila .
- g ++ 5.2+ compila.
¿Por qué el this->
necesario solo en el caso de una lambda genérica?
¿Por qué el this->
no es necesario si la lambda no se pasa para call
?
¿Quién no está cumpliendo con los estándares?
Este es un error de gcc. Desde [expr.prim.lambda]:
El enunciado compuesto de lambda-expression produce el cuerpo de función (8.4) del operador de llamada de función, pero a los efectos de búsqueda de nombre (3.4), determinando el tipo y valor de
this
(9.3.2) y transformando expresiones de id. refiriéndose a los miembros de la clase no estáticos en las expresiones de acceso de los miembros de la clase usando(*this)
(9.3.1), la declaración compuesta se considera en el contexto de la expresión lambda . [Ejemplo:
struct S1 { int x, y; int operator()(int); void f() { [=]()->int { return operator()(this->x + y); // equivalent to S1::operator()(this->x + (*this).y) // this has type S1* }; } };
-Final ejemplo]
Dado que en su ejemplo usted captura this
, la búsqueda de nombre debe incluir miembros de la clase de Example
, que por lo tanto debe encontrar Example::foo
. La búsqueda realizada es idéntica a lo que sucedería si foo(x)
apareciera en el contexto de la expresión lambda misma, es decir, si el código se viera así:
void bar()
{
foo(x); // clearly Example::foo(x);
}
Al menos este error tiene una solución muy simple como se indica en la pregunta: simplemente haz this->foo(x);
.