使用 lambda 时 MSVC vs GCC & Clang Bug
MSVC vs GCC & Clang Bug while using lambdas
我正在尝试 CppCon that uses 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. This can be verified here 中提供的示例。
供参考,示例代码如下:
#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());
}
这里有什么问题(如果有的话),哪个编译器是正确的?
请注意,代码是从他们的官方演示幻灯片中精确复制粘贴的。
这是 MSVC 的问题。 clang 和 g++ 是正确的。
来自 [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; any
other lambda-expression shall not have a capture-default or simple-capture in its lambda-introducer. 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. [ Note: This reaching scope includes any intervening lambda-expressions.
—end note ]
由于 =
是 capture-default
,并且 lambda 不在 block-scope 内,代码无效。
What is the problem here(if any)
请问拒绝编译的编译器怎么说:
error: non-local lambda expression cannot have a capture-default
让我们看看标准是怎么说的:
C++14 draft N4140
A lambda-expression whose smallest enclosing scope is a block scope ([basic.scope.block]) is a local lambda expression; any other lambda-expression shall not have a capture-default or simple-capture in its lambda-introducer. 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. [ Note: This reaching scope includes any intervening lambda-expressions. — 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]).
C++17 的措辞与 C++14 几乎相同。
程序是ill-formed并且诊断信息是正确的。不诊断ill-formedness(icc,msvc)的编译器不符合标准
只需删除 capture-default 即可修复该程序。它无论如何都无法捕获块作用域之外的任何内容,这使得它毫无用处,这就是为什么不允许这样做的原因。 ::g
等全局变量无需捕获即可访问。
我正在尝试 CppCon that uses 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. This can be verified here 中提供的示例。
供参考,示例代码如下:
#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());
}
这里有什么问题(如果有的话),哪个编译器是正确的?
请注意,代码是从他们的官方演示幻灯片中精确复制粘贴的。
这是 MSVC 的问题。 clang 和 g++ 是正确的。
来自 [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; any other lambda-expression shall not have a capture-default or simple-capture in its lambda-introducer. 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. [ Note: This reaching scope includes any intervening lambda-expressions. —end note ]
由于 =
是 capture-default
,并且 lambda 不在 block-scope 内,代码无效。
What is the problem here(if any)
请问拒绝编译的编译器怎么说:
error: non-local lambda expression cannot have a capture-default
让我们看看标准是怎么说的:
C++14 draft N4140
A lambda-expression whose smallest enclosing scope is a block scope ([basic.scope.block]) is a local lambda expression; any other lambda-expression shall not have a capture-default or simple-capture in its lambda-introducer. 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. [ Note: This reaching scope includes any intervening lambda-expressions. — 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]).
C++17 的措辞与 C++14 几乎相同。
程序是ill-formed并且诊断信息是正确的。不诊断ill-formedness(icc,msvc)的编译器不符合标准
只需删除 capture-default 即可修复该程序。它无论如何都无法捕获块作用域之外的任何内容,这使得它毫无用处,这就是为什么不允许这样做的原因。 ::g
等全局变量无需捕获即可访问。