12

Consider the following code:

#include <type_traits>

int main()
{
    auto l = [k = 0]
    {
        static_assert(std::is_same_v<decltype(k), int>);
    };
}
  • clang++ (10.x and trunk) happily compiles the code above.

  • g++ (10.x and trunk) fails to compile the code above with the following error:

    error: static assertion failed
       10 |         static_assert(std::is_same_v<decltype(k), int>);
          |                       ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    Apparently, g++ believes that decltype(k) evaluates to const int.

live example on godbolt.org

Since the type of the data member k should be deduced from 0 (which is a plain, non-const, int), I think that this is a g++ bug. In my mental model, the only thing that is const is the operator() of the lambda, but not the synthesized data member k.

  • Is my assessment correct?

  • What does the standard say?

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • if it helps, clang compiles `static_assert(std::is_same_v);` and gcc compiles `static_assert(std::is_same_v);` so I dont think its an issue with `int i;`. – UnforeseenPrincess Jul 18 '20 at 01:55
  • As far as I can tell, the language only requires that `k` shall not be modified. I'd guess that implementing this by making the synthesized member `const` (as gcc appears to be doing), is allowed, and so both are right. – cigien Jul 18 '20 at 02:54
  • @cigien [Not so sure about that](http://eel.is/c++draft/expr.prim.lambda#capture-6). For the most part, the standard goes to great pains to treat the occurrences of variables inside a lambda body as actually "directly" referring to the things in the enclosing scope, not to the members of the closure type. Apparently it does the same for initializing captures. – HTNW Jul 18 '20 at 03:51
  • [gcc seems a bit confused on what the type of `k` actually is lol. It's `int` on one line, `const int` on the next.](https://gcc.godbolt.org/z/dzozcr). – Rakete1111 Jul 18 '20 at 23:41

1 Answers1

9

The standard is rather explicit in this case. [expr.prim.lambda.capture]/6:

An init-capture without ellipsis behaves as if it declares and explicitly captures a variable of the form “auto init-capture ;” whose declarative region is the lambda-expression's compound-statement, [...]

so your code is (roughly - see the rest of the quote above to see how the two differ) equivalent to the following, which gcc accepts!:

auto k = 0;
auto l = [k]
{
    static_assert(std::is_same_v<decltype(k), int>);
};

So who's right? For that we see that the type of the k, which is int since auto deduces to int for 0.

Then it is only a matter of looking at [dcl.type.decltype]/1.3 which says:

[...] if E [the expression inside decltype] is an unparenthesized id-expression [...], decltype(E) is the type of the entity named by E.

The type of the entity k is int. So gcc is wrong.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162