从通用lambda - clang和gcc调用`this`成员函数 [英] Calling `this` member function from generic lambda - clang vs gcc
问题描述
问题:传递捕获此
的通用lambda (到模板函数),并调用成员函数这个
没有明确的 this->
不能在gcc上编译。如果lambda不是通用的,或者如果lambda没有传递给任何其他函数,但是调用到位,它编译具有显式 this->
。 Clang在所有情况下都很酷。
另一轮 clang vs gcc 的时间。谁是正确的?
template< typename TF>
void call(TF&& f)
{
f(1);
}
struct示例
{
void foo(int){}
void bar()
{
call([this](auto x){foo(x);});
}
};
int main()
{
示例{}。
return 0;
}
- li>
- clang ++ 3.6+ 编译。
- g ++ 5.2+
错误:无法调用成员函数'void Example :: foo(int)'无对象
call ](auto x){foo(x);});`
bar()
= call([this](auto x){foo(x);});
- 使用
bar()
=call([this](auto x){this-> foo(x);});
- clang ++ 3.6+ 编译。
- g ++ 5.2+ 编译 li>
- 使用
bar / code> =
call([this](int x){foo(x);});
- clang ++ 3.6+ 编译。
- g ++ 5.2+ / ul>
- 使用
bar()
=[this](auto x){foo(x); }(1);
- clang ++ 3.6+ 编译。
- g ++ 5.2+ 编译。
<
为什么
this->
仅在通用lambda的情况下才需要?
$如果未将lambda传递给call
,为什么this->
谁不符合标准?
解决方案是一个gcc bug。来自[expr.prim.lambda]:
产生函数调用运算符
的 function-body (8.4),但是为了查找名称(3.4),确定this
(9.3.2)并将 id-expressions
转换为类成员访问表达式中的非静态类成员* this)
(9.3.1),在 lambda-expression 的上下文中考虑复合语句。 [示例:struct S1 {
int x,y;
int operator()(int);
void f(){
[=]() - > int {
return operator()(this-> x + y);
//相当于S1 :: operator()(this-> x +(* this).y)
//这是类型S1 *
}
}
};
-end example]
< blockquote>
由于在您的示例中捕获
this
,名称查找应包括/ code>,因此应该找到
Example :: foo
。执行的查找与如果foo(x)
出现在 lambda-expression 本身的上下文中会发生的情况相同,也就是说如果代码看起来像:void bar()
{
foo(x); //清楚例子:: foo(x);
}
至少这个bug有一个非常简单的解决方法,如问题所示:just do
this-> foo(x);
。Issue: passing a generic lambda (to a template function) that captures
this
and calls a member function ofthis
without an explicitthis->
does not compile on gcc. If the lambda is not generic, or if the lambda is not passed to any other function but called in place, it compiles withoit an explicitthis->
. Clang is cool with the code in all situations.Time for another round of clang vs gcc. Who's right?
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; }
- With
bar()
=call([this](auto x){ foo(x); });
- clang++ 3.6+ compiles.
- g++ 5.2+ does not compile.
error: cannot call member function 'void Example::foo(int)' without object call([this](auto x){ foo(x); });`
- With
bar()
=call([this](auto x){ this->foo(x); });
- clang++ 3.6+ compiles.
- g++ 5.2+ compiles.
- With
bar()
=call([this](int x){ foo(x); });
- clang++ 3.6+ compiles.
- g++ 5.2+ compiles.
- With
bar()
=[this](auto x){ foo(x); }(1);
- clang++ 3.6+ compiles.
- g++ 5.2+ compiles.
Why is the
this->
necessary only in the case of a generic lambda?Why is the
this->
not necessary if the lambda isn't passed tocall
?Who is being non standard-compliant?
解决方案This is a gcc bug. From [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 ]
Since in your example you capture
this
, the name lookup should include class members ofExample
, which should therefore findExample::foo
. The lookup performed is identical to what would happen iffoo(x)
appeared in the context of the lambda-expression itself, that is if the code looked like:void bar() { foo(x); // clearly Example::foo(x); }
At least this bug has a very simple workaround as indicated in the question: just do
this->foo(x);
.这篇关于从通用lambda - clang和gcc调用`this`成员函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!