P0217R3: Wording for structured bindings (original) (raw)

8.5 Decomposition declarations [dcl.decomp]

A decomposition declaration introduces the identifier_s of the_identifier-list as names in the order of appearance, where_vi_ denotes the i_-th identifier, with numbering starting at 1. Let cv denote the_cv-qualifier_s in the decl-specifier-seq. First, a variable with a unique name e is introduced. If the_assignment-expression in the_brace-or-equal-initializer_ has array type A and no_ref-qualifier_ is present, e has type cv A and each element is copy-initialized or direct-initialized from the corresponding element of the assignment-expression as specified by the form of the_brace-or-equal-initializer_. Otherwise, e is defined as-if by

_attribute-specifier-seq_opt decl-specifier-seq _ref-qualifier_opt e brace-or-equal-initializer ;

where the parts of the declaration other than the_declarator-id_ are taken from the corresponding decomposition declaration. The type of the id-expression e is calledE. [ Note: E is never a reference type (Clause 5 [expr]). -- end note ]

If E is an array type with element type T, the number of elements in the identifier-list shall be equal to the number of elements of E. Each vi is the name of an lvalue that refers to the element _i_-1 of the array and whose type is T; the referenced type is T. [ Note: The top-level cv-qualifiers of T are cv. -- end note ] [ Example:

auto f() -> int(&)[2]; auto [ x, y ] = f(); // x and y refer to elements in a copy of the array return value auto& [ xr, yr ] = f(); // xr and yr refer to elements in the array referred to by f's return value

-- end example ]

Otherwise, if the expression std::tuple_size<E>::valueis a well-formed integral constant expression, the number of elements in the identifier-list shall be equal to the value of that expression. The unqualified-id get is looked up in the scope of E by class member access lookup (3.4.5 [basic.lookup.classref]), and if that finds at least one declaration, the initializer is _e_.get<_i_-1>(). Otherwise, the initializer isget<_i_-1>(_e_), where getis looked up in the associated namespaces (3.4.2 [basic.lookup.argdep]). In either case, get<_i_-1> is taken as a template-id. [ Note: Ordinary unqualified lookup (3.4.1 [basic.lookup.unqual]) is not performed. -- end note ] In either case,e is an lvalue if the type of the entity eis an lvalue reference and an xvalue otherwise. Given the type Ti designated bystd::tuple_element<_i_-1,E>::type, each_vi_ is a variable of type "reference to Ti" initialized with the initializer, where the reference is an lvalue reference if the initializer is an lvalue and an rvalue reference otherwise; the referenced type is Ti.

Otherwise, all of E's non-static data members shall be public direct members of E or of the same unambiguous public base class of E, E shall not have an anonymous union member, and the number of elements in the identifier-list shall be equal to the number of non-static data members of E. The i_-th non-static data member of E in declaration order is designated by_mi. Each vi is the name of an lvalue that refers to the member mi ofe and whose type is cv Ti, where Ti is the declared type of that member; the referenced type is cv Ti. The lvalue is a bit-field if that member is a bit-field. [ Example:

struct S { int x1 : 2; volatile double y1; }; S f(); const auto [ x, y ] = f();

The type of the id-expression xis "const int", the type of the id-expression y is "const volatile double". -- end example ]