I've checked the GCC buglist and the Clang buglist and don't see anything relevant yet.
This Wandbox link shows some C++11/C++14 code exercising decltype(x)
and decltype((x))
for various kinds of x
captured by lambdas. GCC and Clang give different answers for this code. Which of them, if either, is correct?
Here's the offending snippet:
// inside main()
int i = 42;
int &j = i;
[j=j](){
static_assert(std::is_same<decltype(j), GCC(const) int>::value,""); // A
static_assert(std::is_same<decltype((j)), const int&>::value,""); // B
}();
[=](){
static_assert(std::is_same<decltype(j), int&>::value,""); // C
static_assert(std::is_same<decltype((j)), CLANG(const) int&>::value,""); // D
}();
I believe that in both cases, the thing that is actually captured(*) is a (non-const) int
initialized to a copy of j
's value (that is to say, i
's value). Since the lambda isn't marked mutable
, its operator()
is going to be a const
member function. With those prerequisites out of the way, let's proceed...
On line // A
, GCC tells me that the decltype of the explicitly init-captured j
is const int
, when I'm almost positive that it ought to be int
(per Clang).
On line // B
, both compilers agree that (j)
is an lvalue referring to a const int (since the lambda is not marked mutable
); this makes perfect sense to me.
On line // C
, both compilers agree that j
is a name referring to the int&
declared on line 2. This is a consequence of 5.1.2 [expr.prim.lambda]/19, or rather, a consequence of the-thing-that-happens-when-that-clause-is-not-being-invoked. Inside a [=]
lambda, the name j
refers to the j
in the outer scope, but the expression (j)
refers to the (j)
that would exist if j
were to have been captured. I don't fully understand how this works or why it's desirable, but there it is. I'm willing to stipulate that this is not a bug in either compiler.
On line // D
, Clang tells me that (j)
is an lvalue referring to a const int, whereas GCC tells me that it's an lvalue referring to a non-const int. I'm pretty sure that Clang is right and GCC is wrong; decltype((j))
should be the same whether j
is captured implicitly or explicitly.
So:
- Are my explanations correct (according to the Standard)?
- Does the correct answer change between C++11 and C++14 (and C++1z)?
- Are
// A
and// D
both bugs in GCC? - Have these bugs been filed already?
(*) — In fact nothing is technically captured by the second lambda, because it doesn't use j
in any evaluated context. That's why lines // A
and // C
give different answers. But I don't know any nice terminology for the-thing-that-is-being-done-to-j
, so I'm just saying "captured".
Aucun commentaire:
Enregistrer un commentaire