Lambda捕获和参数具有相同的名称 – 谁影响其他? (铿锵vs gcc)

auto foo = "You're using g++!"; auto compiler_detector = [foo](auto foo) { std::puts(foo); }; compiler_detector("You're using clang++!"); 
  • 铿锵声++ 3.6.0和更新的打印出“你正在使用铛++!” 并警告捕捉 foo未被使用。

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

什么编译器在这里更精确地遵循C ++标准?

wandbox例子

更新:如底部报价中的核心主席所承诺的那样,代码现在是不合格的 :

如果简单捕获中的标识符出现在lambda声明 参数声明子句参数的声明 id中,则该程序是格式不正确的。


前一段时间里有一些关于lambda的名字查询的问题。 他们被N2927解决了:

新的措辞不再依赖查找来重新映射被捕获实体的使用。 它更明确地否定了lambda 复合语句在两遍中处理的解释,或者复合语句中的任何名字可能parsing为闭包types的成员。

查找总是在lambdaexpression式的上下文中完成的,而不是在转换到闭包types的成员函数体之后。 见[expr.prim.lambda] / 8 :

lambdaexpression式复合语句产生函数调用操作符的函数体 ([dcl.fct.def]),但为了名称查找的目的, 复合语句被认为是在lambdaexpression式 。 [ 例如

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

结束示例 ]

(这个例子也清楚地表明,查找不会考虑封闭types的生成捕获成员。)

foo这个名字在捕获中没有(重新)声明; 它在包含lambdaexpression式的块中声明。 参数foo在嵌套在该外部块中的块中声明(请参见[basic.scope.block] / 2 ,它也明确提到了lambda参数)。 查询的顺序显然是从内部到外部的块 。 因此应该select参数,也就是说,Clang是对的。

如果你要捕获一个初始捕获,即foo = ""而不是foo ,那么答案就不清楚了。 这是因为捕获现在实际上引发了一个没有给出“块” 的声明 。 我给这个核心主席发了消息,他回答说

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

我正在试着收集一些问题的意见给你一个有意义的答案。
首先请注意:

  • 非静态数据成员被声明为每个捕获variables的lambda的lambda
  • 在具体的情况下,lambda有一个闭包types,它有一个公共的内联模板函数调用操作符接受一个名为foo的参数

因此,逻辑会让我乍一看,该参数应该遮蔽捕获的variables,就好像在:

 struct Lambda { template<typename T> void operator()(T foo) const { /* ... */ } private: decltype(outer_foo) foo{outer_foo}; }; 

无论如何,@ nm正确地指出,为复制捕获variables声明的非静态数据成员实际上是未命名的。 也就是说,未命名的数据成员仍然通过标识符(即foo )进行访问。 因此,函数调用操作符的参数名称仍应该(让我说) 影射该标识符
正如在@nm中正确指出的那样:

原始捕获的实体应根据范围规则正常进行遮蔽

正因为如此,我会说铿锵是对的。