Files
cppdraft_translate/cppdraft/dcl/struct/bind.md
2025-10-25 03:02:53 +03:00

216 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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*]