Подтвердить что ты не робот

Вызов функции `this` member из общего лямбда-clang vs gcc

Проблема: передача общей лямбды (в функцию шаблона), которая захватывает this и вызывает функцию-член this без явного this-> не компилируется на gcc. Если лямбда не является общей, или если лямбда не передана какой-либо другой функции, а вызвана на место, она компилируется с явным this->. Clang - это классный код во всех ситуациях.

Время для другого раунда clang vs gcc. Кто прав?

Пример 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;
}

  • С bar()= call([this](auto x){ foo(x); });
    • clang++ 3.6+ компилирует.
    • g++ 5.2+ не компилируется.

      error: невозможно вызвать функцию-член 'void Пример:: foo (int)' без объекта  call ([this] (auto x) {foo (x);}); `


  • С bar()= call([this](auto x){ this->foo(x); });
    • clang++ 3.6+ компилирует.
    • g++ 5.2+ компилируется.

  • С bar()= call([this](int x){ foo(x); });
    • clang++ 3.6+ компилирует.
    • g++ 5.2+ компилируется.

  • С bar()= [this](auto x){ foo(x); }(1);
    • clang++ 3.6+ компилирует.
    • g++ 5.2+ компилируется.

Почему this-> необходимо только в случае общей лямбда?

Почему this-> не требуется, если лямбда не передается в call?

Кто не соответствует стандарту?

4b9b3361

Ответ 1

Это ошибка gcc. Из [expr.prim.lambda]:

Компонентный оператор лямбда-выражений дает функциональное тело (8.4) оператора вызова функции, но для целей поиска по имени (3.4), определяя тип и значение this (9.3.2) и преобразуя выражения id ссылаясь на нестатические члены класса в выражения доступа к членам класса, используя (*this) (9.3.1), составной оператор рассматривается в контексте лямбда-выражения. [Пример:

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*
        };
    }
};

-end пример]

Так как в вашем примере вы записываете this, поиск имени должен включать в себя членов класса Example, поэтому следует найти Example::foo. Выполненный поиск идентичен тому, что произойдет, если foo(x) появится в контексте самого лямбда-выражения, то есть, если код выглядит следующим образом:

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

По крайней мере, эта ошибка имеет очень простой способ обхода, как указано в вопросе: просто this->foo(x);.