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

Ale*_*hev 6 c++ language-lawyer c++11

在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); } ();
  }
};
Run Code Online (Sandbox Code Playgroud)

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

Oli*_*liv 1

在 C++ 标准 \xc2\xa75.1.5 中(C++11 第 7 条,后续标准第 8 条)[expr.prim.lambda]:

\n\n
\n

lambda 表达式\xe2\x80\x99s 复合语句生成函数调用运算符的函数体 (8.4),但\n 出于名称查找 (3.4) 的目的,确定 this 的类型和值 (9.2.2.1 ) 并使用 (*this) (9.2.2) 将引用非静态类成员的 id-\n 表达式转换为类成员访问表达式,\n 复合语句在 lambda 表达式的上下文中考虑。[ 例子:

\n
\n\n
struct S1 {\n  int x, y;\n  int operator()(int);\n  void f() {\n    [=]()->int {\n      return operator()(this->x + y); // equivalent to S1::operator()(this->x + (*this).y)\n                                      // this has type S1*\n               };\n  }\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

\xe2\x80\x94 结束示例]

\n
\n\n

因此,gcc 是正确的。您会注意到,您正在捕获的事实也不例外this。然而,在您捕获 的情况下,它们是自 C++14 以来的精度*this,仍在 \xc2\xa75.1.5 中(第 17 条):

\n\n
\n

如果 *this 是通过复制捕获的,则 this 的每个 odr 使用都会转换为指向闭包类型的相应未命名数据成员的指针,将 (5.4) 强制转换为 this 的类型。

\n
\n