Skip to content

[temp.variadic] Rearrange description of pack expansion #4543

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

Merged
merged 1 commit into from
Jun 18, 2021
Merged
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
86 changes: 43 additions & 43 deletions source/templates.tex
Original file line number Diff line number Diff line change
Expand Up @@ -2800,24 +2800,25 @@
\end{example}

\pnum
The instantiation of a pack expansion
that is neither a \tcode{sizeof...} expression
nor a \grammarterm{fold-expression}
produces a
list of elements
$\mathtt{E}_1,$ $\mathtt{E}_2,$ $\cdots,$ $\mathtt{E}_N$,
The instantiation of a pack expansion considers
items $\tcode{E}_1, \tcode{E}_2, \dotsc, \tcode{E}_N$,
where
$N$ is the number of elements in the pack expansion parameters. Each
$\mathtt{E}_i$ is generated by instantiating the pattern and
$N$ is the number of elements in the pack expansion parameters.
Each $\tcode{E}_i$ is generated by instantiating the pattern and
replacing each pack expansion parameter with its $i^\text{th}$ element.
Such an element, in the context of the instantiation, is interpreted as
follows:
\begin{itemize}
\item
if the pack is a template parameter pack, the element is a template
parameter\iref{temp.param} of the corresponding kind (type or
non-type) designating the $i^\text{th}$
corresponding type or value template argument;
if the pack is a template parameter pack, the element is
an \grammarterm{id-expression}
(for a non-type template parameter pack),
a \grammarterm{typedef-name}
(for a type template parameter pack declared without \tcode{template}), or
a \grammarterm{template-name}
(for a type template parameter pack declared with \tcode{template})
if the pack was introduced by a pack expansion,
Copy link
Contributor

@xmh0511 xmh0511 Jun 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think "if the pack was introduced by a pack expansion" should be removed for bullet 8.1. For example, template<int...N> struct B{ B(){fun(N...);}};, Isn't that each element instantiated in N... does designate the corresponding template argument? However, int... N is just a template parameter pack declaration instead of a pack expansion(where the template parameter pack N is introduced by the parameter pack declaration). If add the condition seems that the latter clause is not suitable for this case. For type template parameter pack, it is the same. template<template<class T>... TMPL> struct C{using T = U<TMPL....>;};, template<class...T> struct D{using T = tuple<T...>;}, in all of these cases, the pack is introduced by the parameter pack declaration that is not a pack expansion itself, but each element actually does designate the ith template argument.

designating the $i^\text{th}$ corresponding type or value template argument;

\item
if the pack is a function parameter pack, the element is an
Expand All @@ -2835,37 +2836,17 @@
that resulted from instantiation of
the \grammarterm{init-capture} pack.
\end{itemize}

All of the $\mathtt{E}_i$ become items in the enclosing list.
\begin{note}
The variety of list varies with the context:
\grammarterm{expression-list},
\grammarterm{base-specifier-list},
\grammarterm{template-argument-list}, etc.
\end{note}
When $N$ is zero, the instantiation of the expansion produces an empty list.
Such an instantiation does not alter the syntactic interpretation of the
enclosing construct, even in cases where omitting the list entirely would
When $N$ is zero, the instantiation of a pack expansion
does not alter the syntactic interpretation of the enclosing construct,
even in cases where omitting the pack expansion entirely would
otherwise be ill-formed or would result in an ambiguity in the grammar.
\begin{example}
\begin{codeblock}
template<class... T> struct X : T... { };
template<class... T> void f(T... values) {
X<T...> x(values...);
}

template void f<>(); // OK: \tcode{X<>} has no base classes
// \tcode{x} is a variable of type \tcode{X<>} that is value-initialized
\end{codeblock}
\end{example}

\pnum
The instantiation of a \tcode{sizeof...} expression\iref{expr.sizeof} produces
an integral constant containing the number of elements in the pack
it expands.
an integral constant with value $N$.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we say that sizeof...(Pack) expands the elements of the pack? I think that this isn't observable, even in the weird alias template cases where you end up with sizeof... applied to something that's not just the name of a pack, so this is probably fine, but it seems slightly surprising. Maybe the wording consistency is worth the modicum of surprise.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p7 status quo: "A pack whose name appears within the pattern of a pack expansion is expanded by that pack expansion."

What else do you want me to say?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I had interpreted that "is expanded by" as being a simple boolean property of the appearance of the pack, tying into the rule that all appearances of a pack need to be expanded, and not anything to do with substitution of the elements of the pack into some enclosing pattern.

But I think it's fine to leave this as you have it. Sure, we'll substitute into the identifier and produce a bunch of id-expressions / template-names/typedef-names naming the elements of the pack, then count them and drop them on the floor, but it doesn't matter that we do so.


\pnum
The instantiation of a \grammarterm{fold-expression} produces:
The instantiation of a \grammarterm{fold-expression}\iref{expr.prim.fold} produces:
\begin{itemize}
\item
\tcode{((}$\mathtt{E}_1$
Expand Down Expand Up @@ -2896,11 +2877,8 @@
\end{itemize}

In each case,
\placeholder{op} is the \grammarterm{fold-operator},
$N$ is the number of elements in the pack expansion parameters,
and each $\mathtt{E}_i$ is generated by instantiating the pattern
and replacing each pack expansion parameter with its $i^\text{th}$ element.
For a binary fold-expression,
\placeholder{op} is the \grammarterm{fold-operator}.
For a binary fold,
$\mathtt{E}$ is generated
by instantiating the \grammarterm{cast-expression}
that did not contain an unexpanded pack.
Expand All @@ -2916,7 +2894,7 @@
\tcode{((true \&\& true) \&\& true) \&\& false},
which evaluates to \tcode{false}.
\end{example}
If $N$ is zero for a unary fold-expression,
If $N$ is zero for a unary fold,
the value of the expression is shown in \tref{temp.fold.empty};
if the operator is not listed in \tref{temp.fold.empty},
the instantiation is ill-formed.
Expand All @@ -2931,6 +2909,28 @@
\tcode{,} & \tcode{void()} \\
\end{floattable}

\pnum
The instantiation of any other pack expansion
produces a list of elements $\tcode{E}_1, \tcode{E}_2, \dotsc, \tcode{E}_N$.
\begin{note}
The variety of list varies with the context:
\grammarterm{expression-list},
\grammarterm{base-specifier-list},
\grammarterm{template-argument-list}, etc.
\end{note}
When $N$ is zero, the instantiation of the expansion produces an empty list.
\begin{example}
\begin{codeblock}
template<class... T> struct X : T... { };
template<class... T> void f(T... values) {
X<T...> x(values...);
}

template void f<>(); // OK: \tcode{X<>} has no base classes
// \tcode{x} is a variable of type \tcode{X<>} that is value-initialized
\end{codeblock}
\end{example}

\rSec2[temp.friend]{Friends}

\pnum
Expand Down