[dcl.struct.bind] (original) (raw)
9 Declarations [dcl]
9.7 Structured binding declarations [dcl.struct.bind]
A structured binding is either an sb-identifier that does not contain an ellipsis or an element of a structured binding pack.
First, a variable with a unique name e is introduced.
Otherwise, _e_is defined as-if by
where the declaration is never interpreted as a function declaration and the parts of the declaration other than the declarator-id are taken from the corresponding structured binding declaration.
The structured binding size of E, as defined below, is the number of structured bindings that need to be introduced by the structured binding declaration.
If there is no structured binding pack, then the number of elements in the sb-identifier-listshall be equal to the structured binding size of E.
Otherwise, the number of non-pack elements shall be no more than the structured binding size of E; the number of elements of the structured binding pack is the structured binding size of E less the number of non-pack elements in thesb-identifier-list.
Let denote the structured binding in the structured binding declaration after expanding the structured binding pack, if any.
[Note 2:
If there is no structured binding pack, then denotes .
— _end note_]
[Example 1: struct C { int x, y, z; };template<class T> void now_i_know_my() { auto [a, b, c] = C(); auto [d, ...e] = C(); auto [...f, g] = C(); auto [h, i, j, ...k] = C(); auto [l, m, n, o, ...p] = C(); } — _end example_]
If a structured binding declaration appears as a condition, the decision variable ([stmt.pre]) of the condition is e.
If the initializer refers to one of the names introduced by the structured binding declaration, the program is ill-formed.
If E is an array type with element type T, the structured binding size of E is equal to the number of elements of E.
Each is the name of an lvalue that refers to the element i of the array and whose type is T; the referenced type is T.
[Note 3:
The top-level cv-qualifiers of T are cv.
— _end note_]
[Example 2: auto f() -> int(&)[2];auto [ x, y ] = f(); auto& [ xr, yr ] = f(); auto g() -> int(&)[4];template<size_t N> void h(int (&arr)[N]) { auto [a, ...b, c] = arr; auto& [...e] = arr; } void call_h() { h(g());} — _end example_]
Otherwise, if the qualified-id std::tuple_size<E>names a complete class type with a member named value, the expression std::tuple_size<E>::valueshall be a well-formed integral constant expression and the structured binding size of E is equal to the value of that expression.
Let i be an index prvalue of type std::size_tcorresponding to .
If a search for the name getin the scope of E ([class.member.lookup]) finds at least one declaration that is a function template whose first template parameter is a constant template parameter, the initializer is_e_.get<i>().
Otherwise, the initializer is get<i>(e), where get undergoes argument-dependent lookup ([basic.lookup.argdep]).
In either case, get<i> is interpreted as a template-id.
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 designated bystd::tuple_element<i, E>::type and the type designated by either & or &&, where is an lvalue reference if the initializer is an lvalue and an rvalue reference otherwise, variables are introduced with unique names as follows:
Each is the name of an lvalue of type that refers to the object bound to ; the referenced type is .
The initialization of e and any conversion of e considered as a decision variable ([stmt.pre]) is sequenced before the initialization of any .
The initialization of each is sequenced before the initialization of any where .
Otherwise, all of E's non-static data members shall be direct members of E or of the same base class of E, well-formed when named as e._name_in the context of the structured binding,E shall not have an anonymous union member, and the structured binding size of E is equal to the number of non-static data members of E.
Designating the non-static data members of E as, , (in declaration order), each is the name of an lvalue that refers to the member m of e and whose type is that of e. ([expr.ref]); the referenced type is the declared type of if that type is a reference type, or the type of e. otherwise.
The lvalue is a bit-field if that member is a bit-field.
[Example 3: struct S { mutable int x1 : 2; volatile double y1; }; S f();const auto [ x, y ] = f();
— _end example_]