examples c++ lambda this language-lawyer c++14

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?

Ejemplo de Wandbox

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