Вызов функции `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
?
Кто не соответствует стандарту?
Ответы
Ответ 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);
.