在括号内的lambda内声明名为`this`的变量会导致3个不同的编译器产生不同的结果

时间:2017-03-01 10:15:01

标签: c++ c++11 language-lawyer

在C ++中,可以在int (x) = 0;之类的括号内声明变量。但似乎如果您使用this而不是变量名,则使用构造函数:A (this);调用A::A(B*)。所以第一个问题是为什么它与this不同,是因为变量不能命名为this?更复杂的是,让this放入lambda -

struct B;
struct A
{
  A (B *) {}
};

struct B 
{
  B ()
  {
    [this] { A (this); } ();
  }
};

现在gcc调用A::A(B*),msvc打印有关缺少默认构造函数和clang打印expected expressionhttps://godbolt.org/g/Vxe0fF)的错误。它甚至在msvc中更有趣 - 它确实创建了可以使用的名称为this的变量,所以它肯定是一个bug(https://godbolt.org/g/iQaaPH)。哪种编译器是正确的,这种行为的原因是什么?

1 个答案:

答案 0 :(得分:1)

在C ++标准§5.1.5(C ++ 11第7条,第8条后标准)中[expr.prim.lambda]:

  

lambda-expression的复合语句产生函数调用操作符的函数体(8.4),但是   为了查找名称(3.4),确定它的类型和值(9.2.2.1)并转换id-   使用(* this)(9.2.2)将非静态类成员引用到类成员访问表达式中的表达式,   复合语句在lambda表达式的上下文中考虑。 [例如:

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

- 结束示例]

因此,gcc是对的。您会注意到他们捕获this这一事实也不例外。然而,在你捕获*this的情况下,它们是自C ++ 14以来的精度,仍然在§5.1.5(第17条)中:

  

如果*这是由副本捕获的,则每次使用它都会转换为指向相应的指针   闭包类型的未命名数据成员,强制转换(5.4)到此类型。