This commit is contained in:
2025-10-25 03:02:53 +03:00
commit 043225d523
3416 changed files with 681196 additions and 0 deletions

215
cppdraft/dcl/struct/bind.md Normal file
View File

@@ -0,0 +1,215 @@
[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.11Identifiers[lex.name]")*s*v0, v1, v2,…,vN−1 of the[*sb-identifier-list*](dcl.pre#nt:sb-identifier-list "9.1Preamble[dcl.pre]") as names[.](#1.sentence-1)
An [*sb-identifier*](dcl.pre#nt:sb-identifier "9.1Preamble[dcl.pre]") that contains an ellipsis
introduces a structured binding pack ([[temp.variadic]](temp.variadic "13.7.4Variadic templates"))[.](#1.sentence-2)
A [*structured binding*](#def:structured_binding "9.7Structured binding declarations[dcl.struct.bind]") is either
an [*sb-identifier*](dcl.pre#nt:sb-identifier "9.1Preamble[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.1Attribute syntax and semantics[dcl.attr.grammar]") of
an [*sb-identifier*](dcl.pre#nt:sb-identifier "9.1Preamble[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.1General[dcl.decl.general]")*s* in
the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") and*S* consist of
each [*decl-specifier*](dcl.spec.general#nt:decl-specifier "9.2.1General[dcl.spec.general]") of the [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") that is constexpr, constinit, or
a [*storage-class-specifier*](dcl.stc#nt:storage-class-specifier "9.2.2Storage class specifiers[dcl.stc]")[.](#1.sentence-5)
A cv that includes volatile is deprecated;
see [[depr.volatile.type]](depr.volatile.type "D.4Deprecated 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.19Assignment and compound assignment operators[expr.assign]") in the [*initializer*](dcl.init.general#nt:initializer "9.5.1General[dcl.init.general]") has array type *cv1* A and no [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1General[dcl.decl.general]") is present,*e* is defined by
[*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute 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.19Assignment and compound assignment operators[expr.assign]") as specified
by the form of the [*initializer*](dcl.init.general#nt:initializer "9.5.1General[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.1Attribute syntax and semantics[dcl.attr.grammar]")opt [*decl-specifier-seq*](dcl.spec.general#nt:decl-specifier-seq "9.2.1General[dcl.spec.general]") [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1General[dcl.decl.general]")opt *e* [*initializer*](dcl.init.general#nt:initializer "9.5.1General[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.1General[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.1General[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.2Properties 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.7Structured 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.1Preamble[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.1Preamble[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.1Preamble[stmt.pre]"),
the decision variable ([[stmt.pre]](stmt.pre "8.1Preamble")) 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.1General[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.3Qualified 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.2Member 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.4Argument-dependent name lookup"))[.](#7.sentence-4)
In either case, get<i> is interpreted as a [*template-id*](temp.names#nt:template-id "13.3Names of template specializations[temp.names]")[.](#7.sentence-5)
[*Note [4](#note-4)*:
Ordinary [unqualified lookup](basic.lookup.unqual "6.5.3Unqualified 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.1General[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.1Preamble"))
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.5Class 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.1General[expr.prim.id.general]") x is “int”,
the type of the [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") y is “const volatile double”[.](#8.sentence-4)
— *end example*]