Skip to content

[dcl.struct.bind] Tuple-like decomposition with prvalues #807

@brevzin

Description

@brevzin

Full name of submitter (unless configured in github; will be published with the issue): Barry Revzin

Reference (section label): dcl.struct.bind

Link to reflector thread (if any):

Issue description:

In the tuple case of structured bindings, we say:

In either case, e is an lvalue if the type of the entity e is an lvalue reference and an xvalue otherwise. Given the type Ti designated by std​::​tuple_element<i, E>​::​type and the type Ui designated by either Ti& or Ti&&, where Ui is an lvalue reference if the initializer is an lvalue and an rvalue reference otherwise, variables are introduced with unique names ri as follows:

S Ui ri = initializer ;

That is, we're always declaring either lvalue references or rvalue references — and then the initializer is either e.get<i>() or get<i>(e). However, what if get returns a prvalue?

In Kona, we adopted P1789, which adds structured bindings support to std::integer_sequence. Per the wording in the paper, this:

constexpr auto [...Is] = std::make_index_sequence<2>();

decomposes into:

constexpr auto e = std::integer_sequence<size_t, 0, 1>();
constexpr size_t&& Is#0 = 0;
constexpr size_t&& Is#1 = 1;

This means that the Is... are mutable, which is surprising, undesired, and violates [expr.const]/9.5 anyway.

We could fix this in the library wording — either by removing the const integer_sequence specialization or making the base specialization make the type T const instead of T. Either the way, the result there would be that the Is... would all be constexpr size_t const&& instead, which would work fine.

But it would probably be less surprising to have the prvalue case in structured bindings simply not be references at all, so that the constexpr would properly propagate const-ness.

Suggested resolution:

Something like this:

Given the type Ti designated by std​::​tuple_element<i, E>​::​type and the type Ui designated by either Ti& or Ti&&, where Ui is an lvalue reference if the initializer is an lvalue and an rvalue reference otherwise Ti if the initializer is a prvalue, Ti& if the initializer is an lvalue, and Ti&& otherwise, variables are introduced with unique names ri as follows:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions