Home > Enterprise >  MSVC vs GCC & Clang Bug while using lambdas
MSVC vs GCC & Clang Bug while using lambdas

Time:04-13

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 slides.

CodePudding user response:

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.

CodePudding user response:

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.

  • Related