从泛型lambda调用`this`成员函数 - clang vs gcc

时间:2015-08-19 14:03:04

标签: c++ lambda this language-lawyer c++14

问题:传递一个普通的lambda (到模板函数),它捕获this并在没有明确的情况下调用this的成员函数this->无法在gcc上编译。如果lambda不是泛型的,或者lambda没有被传递给任何其他函数但是就地调用,它将编译为withoit this->。在所有情况下,Clang对代码很酷。

另一轮 clang vs gcc 的时间。谁是对的?

Wandbox example

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+ 无法编译。
        

      错误:无法调用成员函数'void Example :: 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->仅在通用lambda的情况下是必需的?

如果lambda未传递给this->,为什么call不必要?

谁不符合标准?

1 个答案:

答案 0 :(得分:17)

这是一个gcc错误。来自[expr.prim.lambda]:

  

lambda-expression 复合语句产生函数调用运算符的 function-body (8.4),   但出于名称查找(3.4)的目的,确定this(9.3.2)的类型和值并转换 id-expressions   使用(*this)(9.3.1)将非静态类成员引用到类成员访问表达式中,复合语句 lambda-expression 的上下文中被考虑EM>。 [例如:

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的类成员,因此应找到Example::foo。执行的查找与foo(x)出现在 lambda-expression 本身的上下文中时会发生的情况相同,即代码如下所示:

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

至少这个bug有一个非常简单的解决方法,如问题所示:只做this->foo(x);