简体   繁体   中英

MSVC vs GCC & Clang Bug while using lambdas

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM