According to cppreference, bit-fields can only be captured by copy: https://en.cppreference.com/w/cpp/language/lambda. Period.
At the same time, one can see certain scenarios, e.g.:
struct U {
int i : 4;
};
constexpr int foo() {
const auto & [y] = U{5};
return [&y = y]() { return y; }();
}
static_assert( foo() == 5 );
where both GCC and Clang permit capture of bit-fields by reference even during evaluation of constant expressions. Online demo: https://gcc.godbolt.org/z/bcbqcGKd7
Are there any exceptions not mentioned in cppreference or proposals to future C++ standards, which legalize capture of bit-fields by reference?
Update:
If one replaces the capture in lambda expression with [&y]
:
return [&y]() { return y; }();
then compilers diverge:
error C3693: 'y': bit-fields cannot be captured by reference
foo()
with unrelated error.
Online demo: https://gcc.godbolt.org/z/rTj659ooYSee also: CWG1695
The type of the member of the closure type used to capture y
is const int&
(because the type of x
is const int
)
When you try to bind a const int&
to a bit-field, it binds to a temporary.
The lifetime of this temporary is extended to the lifetime of the lambda (in the same way struct X { const int& r; }; X x{ .r = 3 };
would extend the lifetime of the temporary materialized from 3
).
So you don't capture the bit-field by reference. If it weren't a const
reference:
struct U {
int i : 4;
};
constexpr int foo() {
auto [y] = U{5};
return [&y = y]() { return y; }();
}
static_assert( foo() == 5 );
... it wouldn't compile.
If you made it const
again by making the bit-field const int i : 4;
, it compiles again.