Fedor
Fedor

Reputation: 21307

Capture bit-fields by reference in a lambda expression

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

Upvotes: 2

Views: 111

Answers (1)

Artyer
Artyer

Reputation: 40891

See 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.

Upvotes: 3

Related Questions