C++ Lambda捕获和同名参数-谁在另一个后面隐藏?(叮当声vs海湾合作委员会)

C++ Lambda捕获和同名参数-谁在另一个后面隐藏?(叮当声vs海湾合作委员会),c++,c++11,lambda,language-lawyer,shadowing,C++,C++11,Lambda,Language Lawyer,Shadowing,clang++3.6.0及更新版本打印出“您正在使用clang++!”并警告捕获foo未使用 g++4.9.0及更新版本打印出“您正在使用g++!”,并警告参数foo未使用 P>编译器更准确地遵循C++标准? 我正试图整理一些对这个问题的评论,给你一个有意义的答案。 首先,请注意: 为每个拷贝捕获变量的lambda声明非静态数据成员 在特定情况下,lambda具有闭包类型,该闭包类型具有接受名为foo 因此,逻辑会让我第一眼看到,参数应该隐藏捕获的变量,就像在: auto foo = "

clang++3.6.0及更新版本打印出“您正在使用clang++!”并警告捕获
foo
未使用

  • g++4.9.0及更新版本打印出“您正在使用g++!”,并警告参数
    foo
    未使用

  • <> P>编译器更准确地遵循C++标准?


    我正试图整理一些对这个问题的评论,给你一个有意义的答案。
    首先,请注意:

    • 为每个拷贝捕获变量的lambda声明非静态数据成员
    • 在特定情况下,lambda具有闭包类型,该闭包类型具有接受名为
      foo
    因此,逻辑会让我第一眼看到,参数应该隐藏捕获的变量,就像在:

    auto foo = "You're using g++!";
    auto compiler_detector = [foo](auto foo) { std::puts(foo); };
    compiler_detector("You're using clang++!");
    
    struct Lambda{
    模板void运算符()(T foo)常量{/*…*/}
    私有:decltype(outer_foo)foo{outer_foo};
    };
    
    总之,@n.m.正确地指出,为拷贝捕获变量声明的非静态数据成员实际上未命名。也就是说,未命名的数据成员仍然通过标识符(即
    foo
    )进行访问。因此,函数调用运算符的参数名仍应(让我说)隐藏该标识符。
    正如@n.m.在对问题的评论中正确指出的:

    原始捕获的实体[…]应根据范围规则进行正常阴影处理


    因此,我认为clang是正确的。

    更新:正如核心主席在下面的引文中承诺的,代码是:

    如果简单捕获中的标识符显示为lambda声明符的parameter declaration子句的参数的声明符id,则程序的格式不正确


    不久前,在lambdas中有一些关于名称查找的问题。解决这些问题的办法是:

    新的措辞不再依赖于查找来重新映射捕获实体的使用它更清晰 拒绝解释lambda的复合语句分两次处理,或者该复合语句中的任何名称可能解析为闭包类型的成员。

    查找始终在lambda表达式的上下文中进行,而不是在转换到闭包类型的成员函数体之后进行。见:

    lambda表达式的复合语句生成函数调用运算符的函数体([dcl.fct.def]),但出于名称查找的目的,[…],在lambda表达式的上下文中考虑复合语句。[示例:

    -[结束示例]

    (该示例也清楚地表明,查找并没有考虑关闭类型的生成捕获成员)。 捕获中未(重新)声明名称

    foo
    ;它在包含lambda表达式的块中声明。参数
    foo
    在嵌套在该外部块中的块中声明(请参阅,其中还明确提到lambda参数)。查找的顺序很清楚。因此,应该选择参数,即Clang是正确的

    如果要将捕获设置为初始捕获,即
    foo=”“
    而不是
    foo
    ,则答案将不明确。这是因为现在的捕获实际上没有给出其“块”。我给核心主席发了信息,他回答说

    这是第2211期(一个新的问题列表将很快出现在open-std.org网站上,不幸的是,其中一些问题只有占位符,这就是其中之一;我正在努力在本月底的Kona会议之前填补这些空白)。CWG在我们一月份的电话会议上讨论了这一点,如果捕获名称也是参数名称,则方向是使程序格式错误。


    将代码从wandbox粘贴到(他们似乎忘记了共享按钮)使VS2015(?)似乎同意clang所说的警告C4458:“foo”声明隐藏类成员。很好的示例..lambda有一个带有模板函数调用运算符的类型,因此,逻辑会让我说参数应该隐藏捕获的变量,就像在
    struct Lambda{template void operator()(T foo)const{/*…*/}private:decltype(outer_foo)foo{outer_foo};}
    @nwp VS中错误一样,Lambda的数据成员未命名,因此无法隐藏。该标准说“对捕获实体的访问被转换为对相应数据成员的访问”,这让我们陷入了困境。我希望clang版本是正确的——如果函数外部的东西遮挡了函数参数,而不是相反,这将是一个新的突破!如上所述,在这个上下文中的查找从来不会像在转换的闭包类型中一样执行。@Columbo我添加了一行我遗漏的内容,即使从推理中可以清楚地看出,那就是clang是正确的。有趣的是,我在试图给出答案时发现了[expr.prim.lambda]/8,但我无法像您那样正确地使用它。这就是为什么每次阅读你的答案都是一种乐趣在这里,我没有什么要说的:)一个简单的捕获没有声明任何内容,因此名称查找的正确结果是相当明显的(顺便说一句,如果您使用捕获默认值而不是显式捕获,那么GCC就可以得到正确的结果)。初始化捕获有点棘手。@T.C.我同意。我提出了一个核心问题,但显然这已经讨论过了,见编辑后的答案。
    struct Lambda {
        template<typename T> void operator()(T foo) const { /* ... */ }
        private: decltype(outer_foo) foo{outer_foo};
    };
    
    struct S1 {
      int x, y;
      int operator()(int);
      void f() {
        [=]()->int {
          return operator()(this->x+y);  // equivalent to: S1::operator()(this->x+(*this).y)
                                         // and this has type S1*
        }; 
      }
    };