使用 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 等全局变量无需捕获即可访问。