c++lambdareferencelanguage-lawyerbit-fields

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


Solution

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