从通用 lambda 调用 `this` 成员函数 - clang vs gcc
Calling `this` member function from generic lambda - clang vs gcc
问题: 传递通用 lambda (到模板函数) 捕获 this
并调用的成员函数没有显式 this->
的 this
不会在 gcc 上编译。如果 lambda 不是通用的,或者如果 lambda 没有传递给任何其他函数而是就地调用,它会在没有显式 this->
的情况下进行编译。 Clang 在所有情况下都对代码很酷。
又一轮 clang vs gcc 的时间到了。谁是对的?
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: cannot call member function 'void Example::foo(int)' without object
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+ 编译。
为什么只有在通用 lambda 的情况下才需要 this->
?
如果没有将 lambda 传递给 call
,为什么 this->
不是必需的?
谁不符合标准?
这是一个 gcc 错误。来自 [expr.prim.lambda]:
The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator,
but for purposes of name lookup (3.4), determining the type and value of this
(9.3.2) and transforming id-expressions
referring to non-static class members into class member access expressions using (*this)
(9.3.1), the compound-statement is considered in the context of the lambda-expression. [ Example:
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 example ]
由于在您的示例中您捕获了 this
,名称查找应该包括 Example
的 class 成员,因此应该找到 Example::foo
。执行的查找与 foo(x)
出现在 lambda 表达式 本身的上下文中时发生的查找相同,也就是说,如果代码看起来像:
void bar()
{
foo(x); // clearly Example::foo(x);
}
至少这个错误有一个非常简单的解决方法,如问题中所示:只需执行 this->foo(x);
。
问题: 传递通用 lambda (到模板函数) 捕获 this
并调用的成员函数没有显式 this->
的 this
不会在 gcc 上编译。如果 lambda 不是通用的,或者如果 lambda 没有传递给任何其他函数而是就地调用,它会在没有显式 this->
的情况下进行编译。 Clang 在所有情况下都对代码很酷。
又一轮 clang vs gcc 的时间到了。谁是对的?
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: cannot call member function 'void Example::foo(int)' without object 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+ 编译。
为什么只有在通用 lambda 的情况下才需要 this->
?
如果没有将 lambda 传递给 call
,为什么 this->
不是必需的?
谁不符合标准?
这是一个 gcc 错误。来自 [expr.prim.lambda]:
The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator, but for purposes of name lookup (3.4), determining the type and value of
this
(9.3.2) and transforming id-expressions referring to non-static class members into class member access expressions using(*this)
(9.3.1), the compound-statement is considered in the context of the lambda-expression. [ Example: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 example ]
由于在您的示例中您捕获了 this
,名称查找应该包括 Example
的 class 成员,因此应该找到 Example::foo
。执行的查找与 foo(x)
出现在 lambda 表达式 本身的上下文中时发生的查找相同,也就是说,如果代码看起来像:
void bar()
{
foo(x); // clearly Example::foo(x);
}
至少这个错误有一个非常简单的解决方法,如问题中所示:只需执行 this->foo(x);
。