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); .