[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; };

template<class T>void 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];

template<size_t N>void 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<E> names a complete class type with a member named value,
the expression std​::​tuple_size<E>​::​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<i>()[.](#7.sentence-3)

Otherwise, the initializer is get<i>(*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<i> 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<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*](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<j[.](#7.sentence-11)

[8](#8)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L7749)

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[.](#8.sentence-1)

Designating the non-static data members of E asm0, m1, m2,â¦ (in declaration order),
each SBi is the
name of an lvalue that refers to the member mi of *e* and
whose type is
that of *e*.mi ([[expr.ref]](expr.ref "7.6.1.5 Class member access"));
the referenced type is
the declared type of mi if that type is a reference type, or
the type of *e*.mi otherwise[.](#8.sentence-2)

The lvalue is a
bit-field if that member is a bit-field[.](#8.sentence-3)

[*Example [3](#example-3)*: struct S { mutable int x1 : 2; volatile double y1; };
S f();const auto [ x, y ] = f();

The type of the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") x is âintâ,
the type of the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1 General [expr.prim.id.general]") y is âconst volatile doubleâ[.](#8.sentence-4)

â *end example*]
