32

I would want to use a constexpr value in a lambda. Reading the answer to Using lambda captured constexpr value as an array dimension, I assumed the following should work:

  #include<array>
  int main()
  { 
    constexpr int i = 0;
    auto f = []{  
      std::array<int, i> a;
    };
    return 0;
  }

However, Clang 3.8 (with std=c++14) complains that

variable 'i' cannot be implicitly captured in a lambda with no capture-default specified

Should this be considered a bug in clang 3.8?

BTW:

The above code does compile with gcc 4.9.2. If I change the lambda expresion to capture explicitly:

...
auto f = [i]{
...

clang 3.8 compiles it, but gcc 4.9.2 fails:

error: the value of ‘i’ is not usable in a constant expression ...

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Olaf Booij
  • 323
  • 3
  • 4
  • does `[constexpr int _i =i]{}` does any difference? – David Haim Nov 23 '15 at 15:02
  • Nope, that does not compile under gcc 4.9.2, nor Clang 3.8. – Olaf Booij Nov 23 '15 at 15:12
  • hmmm.... I supposed you thought about #define as a (temprary) solution? – David Haim Nov 23 '15 at 15:14
  • but macros are evil! And plus, they can't be assigned with constexpr function. – Guillaume Racicot Nov 23 '15 at 15:21
  • @GuillaumeRacicot: That's just a mantra. quoting from here: http://stackoverflow.com/questions/14041453/why-are-preprocessor-macros-evil-and-what-are-the-alternatives "Macros are just like any other tool - a hammer used in a murder is not evil because it's a hammer. It is evil in the way the person uses it in that way. If you want to hammer in nails, a hammer is a perfect tool." – Karoly Horvath Nov 23 '15 at 15:27
  • Capturing all by value `[=]` or reference `[&]` works for me under gcc 4.9.0 and clang 3.7. – havogt Nov 23 '15 at 15:31
  • Indeed the capturing all by value [=] or reference [&] also compiles with gcc 4.9.2 and clang 3.8 (experimental btw). Another work-around as pointed in http://stackoverflow.com/q/28763375/1065190 is using a static constexpr. – Olaf Booij Nov 23 '15 at 16:35

1 Answers1

16

Should this be considered a bug in clang 3.8?

Yep. A capture is only needed if [expr.prim.lambda]/12 mandates so:

enter image description here

Note in particular the highlighted example. f(x) does not necessitate x to be captured, because it isn't odr-used (overload resolution selects the overload with the object parameter). The same argumentation applies to your code - [basic.def.odr]/3:

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.20) that does not invoke any non-trivial functions…

This requirement is certainly met.

…and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression (Clause 5).

i is its set of potential results as per [basic.def.odr]/(2.1), and the l-t-r conversion is indeed immediately applied as its passed to a non-type template parameter of object type.

Hence, as we have shown that (12.1) isn't applicable - and (12.2) clearly isn't, either - Clang is wrong in rejecting your snippet.

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • The standard doesn't seem to spend much words on uses of constexpr in lambdas... The code in the example just deals with runtime uses (right?), and compiles fine in both clang 3.8 and g++ 4.9.2. – Olaf Booij Nov 25 '15 at 08:28
  • 1
    Anyways, it indeed does seem wrong in clang. I filed bug https://llvm.org/bugs/show_bug.cgi?id=25627 . – Olaf Booij Nov 25 '15 at 08:29
  • @OlafBooij The point is that it can't be a runtime (=odr-) use, since the variable isn't captured. The fact that it compiles is.. self-explanatory, since it's intended to and the devs may even have tested stuff with that exact example. – Columbo Nov 25 '15 at 09:20
  • 5
    Alas, MSVC, a full decade after C++11, still has no compiler that implements this correctly; MSVC insists on `i` being explicitly captured. – Matthew Feb 22 '21 at 16:53