I was trying out an example presented at 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 .
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. clang and g++ are correct.
From [expr.prim.lambda.capture]/3
(C++17 draft 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 ]
Since =
is a capture-default
, and the lambda is not within a block-scope, the code is not valid.
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
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 wording is nearly identical to 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.
The program can be fixed simply by removing the capture-default. It cannot capture anything outside of a block scope anyway which makes it useless which is why it isn't allowed. Globals such as ::g
can be accessed without capturing them.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.