[dcl.struct.bind] # 9 Declarations [[dcl]](./#dcl) ## 9.7 Structured binding declarations [dcl.struct.bind] [1](#1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7580) A structured binding declaration introduces the [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")*s*v0, v1, v2,…,vN−1 of the[*sb-identifier-list*](dcl.pre#nt:sb-identifier-list "9.1 Preamble [dcl.pre]") as names[.](#1.sentence-1) An [*sb-identifier*](dcl.pre#nt:sb-identifier "9.1 Preamble [dcl.pre]") that contains an ellipsis introduces a structured binding pack ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates"))[.](#1.sentence-2) A [*structured binding*](#def:structured_binding "9.7 Structured binding declarations [dcl.struct.bind]") is either an [*sb-identifier*](dcl.pre#nt:sb-identifier "9.1 Preamble [dcl.pre]") that does not contain an ellipsis or an element of a structured binding pack[.](#1.sentence-3) The optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") of an [*sb-identifier*](dcl.pre#nt:sb-identifier "9.1 Preamble [dcl.pre]") appertains to the associated structured bindings[.](#1.sentence-4) Let cv denote the [*cv-qualifier*](dcl.decl.general#nt:cv-qualifier "9.3.1 General [dcl.decl.general]")*s* in the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") and*S* consist of each [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1 General [dcl.spec.general]") of the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") that is constexpr, constinit, or a [*storage-class-specifier*](dcl.stc#nt:storage-class-specifier "9.2.2 Storage class specifiers [dcl.stc]")[.](#1.sentence-5) A cv that includes volatile is deprecated; see [[depr.volatile.type]](depr.volatile.type "D.4 Deprecated volatile types")[.](#1.sentence-6) First, a variable with a unique name *e* is introduced[.](#1.sentence-7) If the[*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]") in the [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") has array type *cv1* A and no [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]") is present,*e* is defined by [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt *S* cv A *e* ; and each element is copy-initialized or direct-initialized from the corresponding element of the [*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]") as specified by the form of the [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]")[.](#1.sentence-8) Otherwise, *e* is defined as-if by [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")opt [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1 General [dcl.spec.general]") [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]")opt *e* [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") ; where the declaration is never interpreted as a function declaration and the parts of the declaration other than the [*declarator-id*](dcl.decl.general#nt:declarator-id "9.3.1 General [dcl.decl.general]") are taken from the corresponding structured binding declaration[.](#1.sentence-9) The type of the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]")*e* is called E[.](#1.sentence-10) [*Note [1](#note-1)*: E is never a reference type ([[expr.prop]](expr.prop "7.2 Properties of expressions"))[.](#1.sentence-11) — *end note*] [2](#2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7626) The [*structured binding size*](#def:structured_binding_size "9.7 Structured binding declarations [dcl.struct.bind]") of E, as defined below, is the number of structured bindings that need to be introduced by the structured binding declaration[.](#2.sentence-1) If there is no structured binding pack, then the number of elements in the [*sb-identifier-list*](dcl.pre#nt:sb-identifier-list "9.1 Preamble [dcl.pre]") shall be equal to the structured binding size of E[.](#2.sentence-2) 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 the [*sb-identifier-list*](dcl.pre#nt:sb-identifier-list "9.1 Preamble [dcl.pre]")[.](#2.sentence-3) [3](#3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7639) Let SBi denote the ith structured binding in the structured binding declaration after expanding the structured binding pack, if any[.](#3.sentence-1) [*Note [2](#note-2)*: If there is no structured binding pack, then SBi denotes vi[.](#3.sentence-2) — *end note*] [*Example [1](#example-1)*: struct C { int x, y, z; }; templatevoid now_i_know_my() {auto [a, b, c] = C(); // OK, SB0 is a, SB1 is b, and SB2 is cauto [d, ...e] = C(); // OK, SB0 is d, the pack e (v1) contains two structured bindings: SB1 and SB2auto [...f, g] = C(); // OK, the pack f (v0) contains two structured bindings: SB0 and SB1, and SB2 is gauto [h, i, j, ...k] = C(); // OK, the pack k is emptyauto [l, m, n, o, ...p] = C(); // error: structured binding size is too small} — *end example*] [4](#4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7662) If a structured binding declaration appears as a [*condition*](stmt.pre#nt:condition "8.1 Preamble [stmt.pre]"), the decision variable ([[stmt.pre]](stmt.pre "8.1 Preamble")) of the condition is *e*[.](#4.sentence-1) [5](#5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7666) If the [*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") refers to one of the names introduced by the structured binding declaration, the program is ill-formed[.](#5.sentence-1) [6](#6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7671) E shall not be an array type of unknown bound[.](#6.sentence-1) If E is any other array type with element type T, the structured binding size of E is equal to the number of elements of E[.](#6.sentence-2) Each SBi 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[.](#6.sentence-3) [*Note [3](#note-3)*: The top-level cv-qualifiers of T are cv[.](#6.sentence-4) — *end note*] [*Example [2](#example-2)*: auto f() -> int(&)[2];auto [ x, y ] = f(); // x and y refer to elements in a copy of the array return valueauto& [ xr, yr ] = f(); // xr and yr refer to elements in the array referred to by f's return valueauto g() -> int(&)[4]; templatevoid h(int (&arr)[N]) {auto [a, ...b, c] = arr; // a names the first element of the array, b is a pack referring to the second and// third elements, and c names the fourth elementauto& [...e] = arr; // e is a pack referring to the four elements of the array}void call_h() { h(g());} — *end example*] [7](#7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7703) Otherwise, if the [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") std​::​tuple_size names a complete class type with a member named value, the expression std​::​tuple_size​::​value shall be a well-formed integral constant expression and the structured binding size of E is equal to the value of that expression[.](#7.sentence-1) Let i be an index prvalue of type std​::​size_t corresponding to vi[.](#7.sentence-2) If a search for the name get in the scope of E ([[class.member.lookup]](class.member.lookup "6.5.2 Member name 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()[.](#7.sentence-3) Otherwise, the initializer is get(*e*), where get undergoes argument-dependent lookup ([[basic.lookup.argdep]](basic.lookup.argdep "6.5.4 Argument-dependent name lookup"))[.](#7.sentence-4) In either case, get is interpreted as a [*template-id*](temp.names#nt:template-id "13.3 Names of template specializations [temp.names]")[.](#7.sentence-5) [*Note [4](#note-4)*: Ordinary [unqualified lookup](basic.lookup.unqual "6.5.3 Unqualified name lookup [basic.lookup.unqual]") is not performed[.](#7.sentence-6) — *end note*] In either case, *e* is an lvalue if the type of the entity *e* is an lvalue reference and an xvalue otherwise[.](#7.sentence-7) Given the type Ti designated bystd​::​tuple_element​::​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*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") ; Each SBi is the name of an lvalue of type Ti that refers to the object bound to ri; the referenced type is Ti[.](#7.sentence-9) The initialization of *e* and any conversion of *e* considered as a decision variable ([[stmt.pre]](stmt.pre "8.1 Preamble")) is sequenced before the initialization of any ri[.](#7.sentence-10) The initialization of each ri is sequenced before the initialization of any rj where i