6

GCC and Clang do compile the following code:

void Test()
{
   constexpr int Size = 3;
   auto Lambda = [Size]{ int Dim[Size]; };
}

However, VisualStudio 2015 CTP 6 does not. Nevertheless, all 3 compilers are happy with this code:

void Test()
{
   static constexpr int Size = 3;
   auto Lambda = []{ int Dim[Size]; };
}

Which snippet is actually doing it in the correct way? What does the C++ standard say?

This question is related to Lambda capturing constexpr object

Community
  • 1
  • 1
Sergey K.
  • 24,894
  • 13
  • 106
  • 174

1 Answers1

7

C++11 [expr.prim.lambda]/12

If a lambda-expression odr-uses this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression.

and /17

Every id-expression that is an odr-use of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type. [ Note: An id-expression that is not an odr-use refers to the original entity, never to a member of the closure type. [...] — end note ]

So we don't even need to capture Size in the first example (where it is not static), since reading from that variable is not an odr-use since it can appear in a constant expression and the lvalue-to-rvalue conversion is immediately applied to it, [basic.def.odr]/2

A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression and the lvalue-to-rvalue conversion is immediately applied.

(It is not clear to me if the array bounds require an l-t-r conversion, though.)

The same applies when capturing Size by reference, or when capturing Size explicitly (by copy) but not odr-using it: the use of the id-expression Size within the lambda accesses the constexpr variable declared in Test, not any captured member (for capture-by-copy: IFF the access does not constitute an odr-use).

C++14 [expr.prim.lamda]/12 adds some wording for polymorphic lambdas that is irrelevant here, and moves /17 to /18. The rules for odr-use are more complicated, but I'd argue it's not an odr-use for the same underlying reason (reading a compile-time constant).

dyp
  • 38,334
  • 13
  • 112
  • 177
  • Long story short. Is there a bug in VS 2015? – Sergey K. Feb 27 '15 at 11:06
  • 1
    @SergeyK. I guess so. I'll try to look up the recent rules (C++14 and post-C++14) which will probably be a bit different. But I can't imagine them being more restrictive here. – dyp Feb 27 '15 at 11:08