#include <type_traits>
int x = 0;
void f(int const x)
{
static_assert(std::is_const_v<decltype(x)>); // ok
}
int main()
{
int n = 0;
[n, m = n]
{
static_assert(std::is_const_v<decltype(m)>); // ok
static_assert(std::is_const_v<decltype(n)>); // err
};
}
See online demo
Why does decltype(captured_var) not behave as expected?
Note that in decltype(n), n refers to the local variable n defined in main(), but not to the member of the closure type (as you expected).
[expr.prim.lambda.capture]/11
(emphasis mine)
Every id-expression within the compound-statement of a lambda-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 7: An id-expression that is not an odr-use refers to the original entity, never to a member of the closure type. However, such an id-expression can still cause the implicit capture of the entity. — end note]
BTW: Gcc seems declaring the data member as const directly for non-mutable lambdas. That's why it gives const int for decltype(m). According to the standard, [expr.prim.lambda.capture]/10.2
(emphasis mine)
The type of such a data member is the referenced type if the entity is a reference to an object, an lvalue reference to the referenced function type if the entity is a reference to a function, or the type of the corresponding captured entity otherwise.
I think gcc is wrong; decltype(m) should lead to type int. Anyway, decltype(n) does refer to the local variable n, you can confirm that by e.g. changing n's type to int&&.
Gcc LIVE
Clang LIVE
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With