Llamar a la función miembro` this ' desde lambda - clang genérico vs gcc


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 this-> explícito no compila en gcc. Si la lambda no es genérica, o si la lambda no se pasa a ninguna otra función sino que se llama en su lugar, compila withoit un this-> explícito. Clang está bien con el código en todas las situaciones.

Tiempo para otra ronda de clang vs gcc. ¿Quién tiene razón?

Caja de varitas ejemplo


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 objeto call ([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);
    • clang++ 3.6+ compila.
    • g++ 5.2+ compila.

¿Por qué es necesario this-> solo en el caso de una lambda genérica?

¿Por qué no es necesario this-> si no se pasa la lambda a call?

¿Quién no cumple con las normas?

Author: Vittorio Romeo, 2015-08-19

1 answers

Este es un error de gcc. De [expr.prim.lambda]:

La lambda-expression ' s compound-statement produce el function-body (8.4) del operador de llamada a la función, pero para fines de búsqueda de nombres (3.4), determinar el tipo y el valor de this (9.3.2) y transformar id-expressions al referirse a los miembros de clase no estáticos en expresiones de acceso a miembros de clase usando (*this) (9.3.1), la instrucció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*
        };
    }
};

-ejemplo final ]

Dado que en su ejemplo captura this, la búsqueda de nombres debe incluir los 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 propia expresión lambda, es decir, si el código se viera como:

void bar()
{
    foo(x); // clearly Example::foo(x);
}

Al menos este error tiene un muy simple solución como se indica en la pregunta: simplemente haga this->foo(x);.

 15
Author: Barry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-19 14:50:01