[英]MSVC vs GCC & Clang Bug while using lambdas
I was trying out an example presented at CppCon that uses lambdas .我正在尝试在CppCon上展示的一个使用lambdas的示例。 And to my surprise the program don't compile in gcc and clang(in either C++14 or C++17) but compiles in msvc.
令我惊讶的是,该程序没有在 gcc 和 clang 中编译(在 C++14 或 C++17 中),而是在 msvc 中编译。 This can be verified here .
这可以在这里验证。
For reference, the example code is as follows:作为参考,示例代码如下:
#include <stdio.h>
int g = 10;
auto kitten = [=]() { return g+1; };
auto cat = [g=g]() { return g+1; };
int main() {
g = 20;
printf("%d %d\n", kitten(), cat());
}
What is the problem here(if any) and which compiler is right?这里有什么问题(如果有的话),哪个编译器是正确的?
Note that the code is an exact copy-paste from their official presentation slide.请注意,该代码是从他们的官方演示幻灯片中精确复制粘贴的。
This is a problem with MSVC.这是 MSVC 的问题。 clang and g++ are correct.
clang 和 g++ 是正确的。
From [expr.prim.lambda.capture]/3
(C++17 draft N4659)来自
[expr.prim.lambda.capture]/3
(C++17 草案 N4659)
A lambda-expression whose smallest enclosing scope is a block scope (6.3.3) is a local lambda expression;
其最小封闭 scope 是块 scope (6.3.3) 的 lambda 表达式是本地 lambda 表达式; any other lambda-expression shall not have a capture-default or simple-capture in its lambda-introducer.
任何其他 lambda 表达式在其 lambda 引入器中不得有捕获默认或简单捕获。 The reaching scope of a local lambda expression is the set of enclosing scopes up to and including the innermost enclosing function and its parameters.
局部 lambda 表达式的到达 scope 是封闭范围的集合,直到并包括最里面的封闭 function 及其参数。 [ Note: This reaching scope includes any intervening lambda-expressions.
[注意:达到 scope 包括任何中间的 lambda 表达式。 —end note ]
——尾注]
Since =
is a capture-default
, and the lambda is not within a block-scope, the code is not valid.由于
=
是capture-default
,并且 lambda 不在块范围内,因此代码无效。
What is the problem here(if any)
这里有什么问题(如果有的话)
Let's ask what the compilers that refuse to compile have to say:让我们问一下拒绝编译的编译器有什么要说的:
error: non-local lambda expression cannot have a capture-default
Let's see what the standard has to say:让我们看看标准是怎么说的:
C++14 draft N4140
C++14 草案 N4140
A lambda-expression whose smallest enclosing scope is a block scope ([basic.scope.block]) is a local lambda expression;
最小封闭 scope 是块 scope ([basic.scope.block]) 的 lambda 表达式是一个局部 lambda 表达式; any other lambda-expression shall not have a capture-default or simple-capture in its lambda-introducer.
任何其他 lambda 表达式在其 lambda 引入器中不得有捕获默认或简单捕获。 The reaching scope of a local lambda expression is the set of enclosing scopes up to and including the innermost enclosing function and its parameters.
局部 lambda 表达式的到达 scope 是封闭范围的集合,直到并包括最里面的封闭 function 及其参数。 [ Note: This reaching scope includes any intervening lambda-expressions.
[注意:达到 scope 包括任何中间的 lambda 表达式。 — end note ]
——尾注]
latest draft
最新草案
A lambda-expression shall not have a capture-default or simple-capture in its lambda-introducer unless its innermost enclosing scope is a block scope ([basic.scope.block]) or it appears within a default member initializer and its innermost enclosing scope is the corresponding class scope ([basic.scope.class]).
lambda 表达式在其 lambda 引入器中不应包含捕获默认值或简单捕获,除非其最内层的封闭 scope 是一个块 scope([basic.scope.block])或者它出现在默认成员初始化器及其最内层的封闭scope对应的是class scope([basic.scope.class])。
C++17 wording is nearly identical to C++14. C++17 的措辞与 C++14 几乎相同。
The program is ill-formed and the diagnostic message is correct.程序格式错误,诊断消息正确。 The compilers that don't diagnose the ill-formedness (icc, msvc) don't conform to the standard.
不诊断格式错误的编译器(icc、msvc)不符合标准。
The program can be fixed simply by removing the capture-default.该程序可以简单地通过删除 capture-default 来修复。 It cannot capture anything outside of a block scope anyway which makes it useless which is why it isn't allowed.
无论如何,它无法捕获块 scope 之外的任何内容,这使得它无用,这就是为什么不允许它。 Globals such as
::g
can be accessed without capturing them.可以在不捕获它们的情况下访问诸如
::g
之类的全局变量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.