Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

P1061R10 Structured Bindings can introduce a Pack #7446

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 75 additions & 18 deletions source/declarations.tex
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,19 @@
\end{bnf}

\begin{bnf}
\nontermdef{attributed-identifier}\br
identifier \opt{attribute-specifier-seq}
\nontermdef{sb-identifier}\br
\opt{\terminal{...}} identifier \opt{attribute-specifier-seq}
\end{bnf}

\begin{bnf}
\nontermdef{attributed-identifier-list}\br
attributed-identifier\br
attributed-identifier-list \terminal{,} attributed-identifier
\nontermdef{sb-identifier-list}\br
sb-identifier\br
sb-identifier-list \terminal{,} sb-identifier
\end{bnf}

\begin{bnf}
\nontermdef{structured-binding-declaration}\br
\opt{attribute-specifier-seq} decl-specifier-seq \opt{ref-qualifier} \terminal{[} attributed-identifier-list \terminal{]}
\opt{attribute-specifier-seq} decl-specifier-seq \opt{ref-qualifier} \terminal{[} sb-identifier-list \terminal{]}
\end{bnf}

\begin{bnf}
Expand Down Expand Up @@ -217,6 +217,10 @@
\tcode{thread_local},
\tcode{auto}\iref{dcl.spec.auto}, or
a \grammarterm{cv-qualifier}.
The declaration shall contain at most one \grammarterm{sb-identifier}
whose \grammarterm{identifier} is preceded by an ellipsis.
If the declaration contains any such \grammarterm{sb-identifier},
it shall declare a templated entity\iref{temp.pre}.
\begin{example}
\begin{codeblock}
template<class T> concept C = true;
Expand Down Expand Up @@ -7019,13 +7023,17 @@

\pnum
A structured binding declaration introduces the \grammarterm{identifier}{s}
$\tcode{v}_0$, $\tcode{v}_1$, $\tcode{v}_2, \dotsc$
$\tcode{v}_0$, $\tcode{v}_1$, $\tcode{v}_2, \dotsc, \tcode{v}_{N-1}$
of the
\grammarterm{attributed-identifier-list} as names
of \defn{structured binding}{s}.
\grammarterm{sb-identifier-list} as names.
An \grammarterm{sb-identifier} that contains an ellipsis
introduces a structured binding pack\iref{temp.variadic}.
A \defn{structured binding} is either
an \grammarterm{sb-identifier} that does not contain an ellipsis or
an element of a structured binding pack.
The optional \grammarterm{attribute-specifier-seq} of
an \grammarterm{attributed-identifier}
appertains to the structured binding so introduced.
an \grammarterm{sb-identifier}
appertains to the associated structured bindings.
Let \cv{} denote the \grammarterm{cv-qualifier}{s} in
the \grammarterm{decl-specifier-seq} and
\placeholder{S} consist of the \grammarterm{storage-class-specifier}{s} of
Expand Down Expand Up @@ -7057,6 +7065,42 @@
\tcode{E} is never a reference type\iref{expr.prop}.
\end{note}

\pnum
The \defn{structured binding size} of \tcode{E}, as defined below,
is the number of structured bindings
that need to be introduced by the structured binding declaration.
If there is no structured binding pack,
then the number of elements in the \grammarterm{sb-identifier-list}
shall be equal to the structured binding size of \tcode{E}.
Otherwise, the number of non-pack elements shall be no more than
the structured binding size of \tcode{E};
the number of elements of the structured binding pack is
the structured binding size of \tcode{E} less
the number of non-pack elements in the\grammarterm{sb-identifier-list}.

\pnum
Let $\textrm{SB}_i$ denote
the $i^\textrm{th}$ structured binding in the structured binding declaration
after expanding the structured binding pack, if any.
\begin{note}
If there is no structured binding pack,
then $\textrm{SB}_i$ denotes $\tcode{v}_i$.
\end{note}
\begin{example}
\begin{codeblock}
struct C { int x, y, z; };

template<class T>
void now_i_know_my() {
auto [a, b, c] = C(); // OK, $\textrm{SB}_0$ is \tcode{a}, $\textrm{SB}_1$ is \tcode{b}, and $\textrm{SB}_2$ is \tcode{c}
auto [d, ...e] = C(); // OK, $\textrm{SB}_0$ is \tcode{d}, the pack \tcode{e} $(\tcode{v}_1)$ contains two structured bindings: $\textrm{SB}_1$ and $\textrm{SB}_2$
auto [...f, g] = C(); // OK, the pack \tcode{f} $(\tcode{v}_0)$ contains two structured bindings: $\textrm{SB}_0$ and $\textrm{SB}_1$, and $\textrm{SB}_2$ is \tcode{g}
auto [h, i, j, ...k] = C(); // OK, the pack \tcode{k} is empty
auto [l, m, n, o, ...p] = C(); // error: structured binding size is too small
}
\end{codeblock}
\end{example}

\pnum
If a structured binding declaration appears as a \grammarterm{condition},
the decision variable\iref{stmt.pre} of the condition is \exposid{e}.
Expand All @@ -7067,9 +7111,10 @@
the program is ill-formed.

\pnum
If \tcode{E} is an array type with element type \tcode{T}, the number
of elements in the \grammarterm{attributed-identifier-list} shall be equal to the
number of elements of \tcode{E}. Each $\tcode{v}_i$ is the name of an
If \tcode{E} is an array type with element type \tcode{T},
the structured binding size of \tcode{E} is equal to the
number of elements of \tcode{E}.
Each $\textrm{SB}_i$ is the name of an
lvalue that refers to the element $i$ of the array and whose type
is \tcode{T}; the referenced type is \tcode{T}.
\begin{note}
Expand All @@ -7080,6 +7125,19 @@
auto f() -> int(&)[2];
auto [ x, y ] = f(); // \tcode{x} and \tcode{y} refer to elements in a copy of the array return value
auto& [ xr, yr ] = f(); // \tcode{xr} and \tcode{yr} refer to elements in the array referred to by \tcode{f}'s return value

auto g() -> int(&)[4];

template<size_t N>
void h(int (&arr)[N]) {
auto [a, ...b, c] = arr; // \tcode{a} names the first element of the array, \tcode{b} is a pack referring to the second and
// third elements, and \tcode{c} names the fourth element
auto& [...e] = arr; // \tcode{e} is a pack referring to the four elements of the array
}

void call_h() {
h(g());
}
\end{codeblock}
\end{example}

Expand All @@ -7090,8 +7148,7 @@
the expression \tcode{std::tuple_size<E>::value}
shall be a well-formed integral constant expression
and
the number of elements in
the \grammarterm{attributed-identifier-list} shall be equal to the value of that
the structured binding size of \tcode{E} is equal to the value of that
expression.
Let \tcode{i} be an index prvalue of type \tcode{std::size_t}
corresponding to $\tcode{v}_i$.
Expand Down Expand Up @@ -7121,7 +7178,7 @@
\placeholder{S} \terminal{U$_i$ r$_i$ =} initializer \terminal{;}
\end{ncbnf}

Each $\tcode{v}_i$ is the name of an lvalue of type $\tcode{T}_i$
Each $\textrm{SB}_i$ is the name of an lvalue of type $\tcode{T}_i$
that refers to the object bound to $\tcode{r}_i$;
the referenced type is $\tcode{T}_i$.
The initialization of \exposid{e} and
Expand All @@ -7139,7 +7196,7 @@
well-formed when named as \tcode{\exposidnc{e}.\placeholder{name}}
in the context of the structured binding,
\tcode{E} shall not have an anonymous union member, and
the number of elements in the \grammarterm{attributed-identifier-list} shall be
the structured binding size of \tcode{E} is
equal to the number of non-static data members of \tcode{E}.
Designating the non-static data members of \tcode{E} as
$\tcode{m}_0$, $\tcode{m}_1$, $\tcode{m}_2, \dotsc$
Expand Down
3 changes: 3 additions & 0 deletions source/expressions.tex
Original file line number Diff line number Diff line change
Expand Up @@ -2844,6 +2844,9 @@
}
\end{codeblock}
\end{example}

\pnum
A fold expression is a pack expansion.
\indextext{expression!fold|)}%

\rSec2[expr.prim.req]{Requires expressions}
Expand Down
2 changes: 1 addition & 1 deletion source/preprocessor.tex
Original file line number Diff line number Diff line change
Expand Up @@ -1895,7 +1895,7 @@
\defnxname{cpp_sized_deallocation} & \tcode{201309L} \\ \rowsep
\defnxname{cpp_static_assert} & \tcode{202306L} \\ \rowsep
\defnxname{cpp_static_call_operator} & \tcode{202207L} \\ \rowsep
\defnxname{cpp_structured_bindings} & \tcode{202403L} \\ \rowsep
\defnxname{cpp_structured_bindings} & \tcode{202411L} \\ \rowsep
\defnxname{cpp_template_template_args} & \tcode{201611L} \\ \rowsep
\defnxname{cpp_threadsafe_static_init} & \tcode{200806L} \\ \rowsep
\defnxname{cpp_unicode_characters} & \tcode{200704L} \\ \rowsep
Expand Down
51 changes: 49 additions & 2 deletions source/templates.tex
Original file line number Diff line number Diff line change
Expand Up @@ -2809,11 +2809,27 @@
\end{codeblock}
\end{example}

\pnum
A \defn{structured binding pack} is an \grammarterm{sb-identifier}
that introduces zero or more structured bindings\iref{dcl.struct.bind}.
\begin{example}
\begin{codeblock}
auto foo() -> int(&)[2];

template <class T>
void g() {
auto [...a] = foo(); // \tcode{a} is a structured binding pack containing two elements
auto [b, c, ...d] = foo(); // \tcode{d} is a structured binding pack containing zero elements
}
\end{codeblock}
\end{example}

\pnum
A \defn{pack} is
a template parameter pack,
a function parameter pack,
or an \grammarterm{init-capture} pack.
an \grammarterm{init-capture} pack, or
a structured binding pack.
The number of elements of a template parameter pack
or a function parameter pack
is the number of arguments provided for the parameter pack.
Expand Down Expand Up @@ -2976,7 +2992,14 @@
designating the variable introduced by
the $i^\text{th}$ \grammarterm{init-capture}
that resulted from instantiation of
the \grammarterm{init-capture} pack declaration.
the \grammarterm{init-capture} pack declaration;
otherwise

\item
if the pack is a structured binding pack,
the element is an \grammarterm{id-expression}
designating the $i^\textrm{th}$ structured binding in the pack
that resulted from the structured binding declaration.
\end{itemize}
When $N$ is zero, the instantiation of a pack expansion
does not alter the syntactic interpretation of the enclosing construct,
Expand Down Expand Up @@ -5304,6 +5327,28 @@
a structured binding declaration\iref{dcl.struct.bind} whose
\grammarterm{brace-or-equal-initializer} is type-dependent,
\item
associated by name lookup with a pack,
\begin{example}
\begin{codeblock}
struct C { };

void g(...); // \#1

template <typename T>
void f() {
C arr[1];
auto [...e] = arr;
g(e...); // calls \#2
}

void g(C); // \#2

int main() {
f<int>();
}
\end{codeblock}
\end{example}
\item
associated by name lookup with
an entity captured by copy\iref{expr.prim.lambda.capture}
in a \grammarterm{lambda-expression}
Expand Down Expand Up @@ -5481,6 +5526,8 @@
\keyword{sizeof} \terminal{...} \terminal{(} identifier \terminal{)}\br
fold-expression
\end{ncsimplebnf}
unless the \grammarterm{identifier} is a structured binding pack
whose initializer is not dependent.

\pnum
An expression of the form \tcode{\&}\grammarterm{qualified-id} where the
Expand Down
Loading