diff --git a/source/basic.tex b/source/basic.tex index 7b29e927dd..32a9138f58 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -2170,7 +2170,7 @@ followed by a \tcode{::} scope resolution operator considers only namespaces, types, and templates whose specializations are types. -If a name, \grammarterm{template-id}, or \grammarterm{decltype-specifier} +If a name, \grammarterm{template-id}, or \grammarterm{computed-type-specifier} is followed by a \tcode{::}, it shall designate a namespace, class, enumeration, or dependent type, and the \tcode{::} is never interpreted as diff --git a/source/classes.tex b/source/classes.tex index a90967fe86..8f53f69d50 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -2188,7 +2188,7 @@ In an explicit destructor call, the destructor is specified by a \tcode{\~{}} followed by a -\grammarterm{type-name} or \grammarterm{decltype-specifier} +\grammarterm{type-name} or \grammarterm{computed-type-specifier} that denotes the destructor's class type. The invocation of a destructor is subject to the usual rules for member functions\iref{class.mfct}; @@ -3397,16 +3397,16 @@ \begin{bnf} \nontermdef{base-specifier}\br - \opt{attribute-specifier-seq} class-or-decltype\br - \opt{attribute-specifier-seq} \keyword{virtual} \opt{access-specifier} class-or-decltype\br - \opt{attribute-specifier-seq} access-specifier \opt{\keyword{virtual}} class-or-decltype + \opt{attribute-specifier-seq} class-or-computed-type-specifier\br + \opt{attribute-specifier-seq} \keyword{virtual} \opt{access-specifier} class-or-computed-type-specifier\br + \opt{attribute-specifier-seq} access-specifier \opt{\keyword{virtual}} class-or-computed-type-specifier \end{bnf} \begin{bnf} -\nontermdef{class-or-decltype}\br +\nontermdef{class-or-computed-type-specifier}\br \opt{nested-name-specifier} type-name\br nested-name-specifier \keyword{template} simple-template-id\br - decltype-specifier + computed-type-specifier \end{bnf} \indextext{specifier access|see{access specifier}}% diff --git a/source/compatibility.tex b/source/compatibility.tex index 70716c9d45..895aed4848 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -31,6 +31,29 @@ bool b = ne({2,3}, {1,2,3}); // unspecified result; previously \tcode{false} \end{codeblock} +\rSec2[diff.cpp23.dcl.dcl]{\ref{dcl.dcl}: Declarations} + +\diffref{dcl.array} +\change +Previously, \tcode{T...[n]} would declare a pack of function parameters. +\tcode{T...[n]} is now a \grammarterm{pack-index-specifier}. +\rationale +Improve the handling of packs. +\effect +Valid \CppXXIII{} code that declares a pack of parameters +without specifying a \grammarterm{declarator-id} becomes ill-formed. +For example: +\begin{codeblock} +template +void f(T... [1]); +template +void g(T... ptr[1]); +int main() { + f(nullptr, nullptr); // ill-formed, previously \tcode{void f(int [1], double [1])} + g(nullptr, nullptr); // ok +} +\end{codeblock} + \rSec2[diff.cpp23.strings]{\ref{strings}: strings library} \diffref{string.conversions} diff --git a/source/declarations.tex b/source/declarations.tex index 929bd6a027..dad9a14a9c 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -1285,7 +1285,7 @@ \nontermdef{simple-type-specifier}\br \opt{nested-name-specifier} type-name\br nested-name-specifier \keyword{template} simple-template-id\br - decltype-specifier\br + computed-type-specifier\br placeholder-type-specifier\br \opt{nested-name-specifier} template-name\br \keyword{char}\br @@ -1311,6 +1311,12 @@ typedef-name \end{bnf} +\begin{bnf} +\nontermdef{computed-type-specifier}\br + decltype-specifier\br + pack-index-specifier +\end{bnf} + \pnum \indextext{component name} The component names of a \grammarterm{simple-type-specifier} are those of its @@ -1382,6 +1388,7 @@ \grammarterm{type-name} & the type named \\ \grammarterm{simple-template-id} & the type as defined in~\ref{temp.names}\\ \grammarterm{decltype-specifier} & the type as defined in~\ref{dcl.type.decltype}\\ +\grammarterm{pack-index-specifier} & the type as defined in~\ref{dcl.type.pack.index}\\ \grammarterm{placeholder-type-specifier} & the type as defined in~\ref{dcl.spec.auto}\\ \grammarterm{template-name} & the type as defined in~\ref{dcl.type.class.deduct}\\ @@ -1431,6 +1438,32 @@ forces \tcode{char} objects to be signed; it is redundant in other contexts. \end{note} +\rSec3[dcl.type.pack.index]{Pack indexing specifier} + +\begin{bnf} +\nontermdef{pack-index-specifier}\br + typedef-name \terminal{...} \terminal{[} constant-expression \terminal{]} +\end{bnf} + +\pnum +The \grammarterm{typedef-name} $P$ in a \grammarterm{pack-index-specifier} +shall denote a pack. + +\pnum +The \grammarterm{constant-expression} shall be +a converted constant expression\iref{expr.const} of type \tcode{std::size_t} +whose value $V$, termed the index, +is such that $0 \le V < \tcode{sizeof...(}P\tcode{)}$. + +\pnum +A \grammarterm{pack-index-specifier} is a pack expansion\iref{temp.variadic}. + +\pnum +\begin{note} +The \grammarterm{pack-index-specifier} denotes +the type of the $V^\tcode{th}$ element of the pack\iref{temp.variadic}. +\end{note} + \rSec3[dcl.type.elab]{Elaborated type specifiers}% \indextext{type specifier!elaborated}% \indextext{\idxcode{typename}}% @@ -1604,6 +1637,13 @@ decltype(i) x2; // type is \tcode{int} decltype(a->x) x3; // type is \tcode{double} decltype((a->x)) x4 = x3; // type is \tcode{const double\&} + +void f() { + [](auto ...pack) { + decltype(pack...[0]) x5; // type is \tcode{int} + decltype((pack...[0])) x6; // type is \tcode{int\&} + }(0); +} \end{codeblock} \end{example} \begin{note} @@ -2366,7 +2406,6 @@ \begin{bnf} \nontermdef{noptr-abstract-pack-declarator}\br noptr-abstract-pack-declarator parameters-and-qualifiers\br - noptr-abstract-pack-declarator \terminal{[} \opt{constant-expression} \terminal{]} \opt{attribute-specifier-seq}\br \terminal{...} \end{bnf} diff --git a/source/expressions.tex b/source/expressions.tex index d44a832ce4..cf08d339ce 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -1325,7 +1325,8 @@ \begin{bnf} \nontermdef{id-expression}\br unqualified-id\br - qualified-id + qualified-id\br + pack-index-expression \end{bnf} \pnum @@ -1430,7 +1431,7 @@ conversion-function-id\br literal-operator-id\br \terminal{\~} type-name\br - \terminal{\~} decltype-specifier\br + \terminal{\~} computed-type-specifier\br template-id \end{bnf} @@ -1447,7 +1448,7 @@ \grammarterm{conversion-function-id}{s}, see~\ref{class.conv.fct}; for \grammarterm{literal-operator-id}{s}, see~\ref{over.literal}; for \grammarterm{template-id}{s}, see~\ref{temp.names}. -A \grammarterm{type-name} or \grammarterm{decltype-specifier} +A \grammarterm{type-name} or \grammarterm{computed-type-specifier} prefixed by \tcode{\~} denotes the destructor of the type so named; see~\ref{expr.prim.id.dtor}. Within the definition of a non-static member function, an @@ -1595,7 +1596,7 @@ \terminal{::}\br type-name \terminal{::}\br namespace-name \terminal{::}\br - decltype-specifier \terminal{::}\br + computed-type-specifier \terminal{::}\br nested-name-specifier identifier \terminal{::}\br nested-name-specifier \opt{\keyword{template}} simple-template-id \terminal{::} \end{bnf} @@ -1633,8 +1634,8 @@ \pnum The \grammarterm{nested-name-specifier} \tcode{::} nominates the global namespace. -A \grammarterm{nested-name-specifier} with a \grammarterm{decltype-specifier} -nominates the type denoted by the \grammarterm{decltype-specifier}, +A \grammarterm{nested-name-specifier} with a \grammarterm{computed-type-specifier} +nominates the type denoted by the \grammarterm{computed-type-specifier}, which shall be a class or enumeration type. If a \grammarterm{nested-name-specifier} $N$ is declarative and @@ -1666,9 +1667,9 @@ \pnum A \grammarterm{qualified-id} shall not be of the form \grammarterm{nested-name-specifier} \opt{\keyword{template}} \tcode{\~} -\grammarterm{decltype-specifier} +\grammarterm{computed-type-specifier} nor of the form -\grammarterm{decltype-specifier} \tcode{::} \tcode{\~} \grammarterm{type-name}. +\grammarterm{computed-type-specifier} \tcode{::} \tcode{\~} \grammarterm{type-name}. \pnum The result of a \grammarterm{qualified-id} $Q$ is @@ -1690,6 +1691,32 @@ \end{itemize} and a prvalue otherwise. +\rSec3[expr.prim.pack.index]{Pack indexing expression} + +\begin{bnf} +\nontermdef{pack-index-expression}\br + id-expression \terminal{...} \terminal{[} constant-expression \terminal{]} +\end{bnf} + +\pnum +The \grammarterm{id-expression} $P$ in a \grammarterm{pack-index-expression} +shall be an \grammarterm{identifier} that denotes a pack. + +\pnum +The \grammarterm{constant-expression} shall be +a converted constant expression\iref{expr.const} of type \tcode{std::size_t} +whose value $V$, termed the index, +is such that $0 \le V < \tcode{sizeof...(}P\tcode{)}$. + +\pnum +A \grammarterm{pack-index-expression} is a pack expansion\iref{temp.variadic}. + +\pnum +\begin{note} +A \grammarterm{pack-index-expression} denotes +the $V^\tcode{th}$ element of the pack\iref{temp.variadic}. +\end{note} + \rSec3[expr.prim.id.dtor]{Destruction} \pnum @@ -4689,14 +4716,14 @@ \end{note} There is an ambiguity in the grammar when \tcode{\~{}} is followed by -a \grammarterm{type-name} or \grammarterm{decltype-specifier}. +a \grammarterm{type-name} or \grammarterm{computed-type-specifier}. The ambiguity is resolved by treating \tcode{\~{}} as the operator rather than as the start of an \grammarterm{unqualified-id} naming a destructor. \begin{note} Because the grammar does not permit an operator to follow the \tcode{.}, \tcode{->}, or \tcode{::} tokens, a \tcode{\~{}} followed by -a \grammarterm{type-name} or \grammarterm{decltype-specifier} in a +a \grammarterm{type-name} or \grammarterm{computed-type-specifier} in a member access expression or \grammarterm{qualified-id} is unambiguously parsed as a destructor name. \end{note} diff --git a/source/preprocessor.tex b/source/preprocessor.tex index 1d32a61af0..7ca4deabb0 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -1851,6 +1851,7 @@ \defnxname{cpp_nontype_template_args} & \tcode{201911L} \\ \rowsep \defnxname{cpp_nontype_template_parameter_auto} & \tcode{201606L} \\ \rowsep \defnxname{cpp_nsdmi} & \tcode{200809L} \\ \rowsep +\defnxname{cpp_pack_indexing} & \tcode{202311L} \\ \rowsep \defnxname{cpp_placeholder_variables} & \tcode{202306L} \\ \rowsep \defnxname{cpp_range_based_for} & \tcode{202211L} \\ \rowsep \defnxname{cpp_raw_strings} & \tcode{200710L} \\ \rowsep diff --git a/source/templates.tex b/source/templates.tex index f107d82813..ce2d7da933 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -2144,6 +2144,19 @@ e.g., by a \grammarterm{typedef-name}. \end{note} +\pnum +For a type template parameter pack \tcode{T}, +\tcode{T...[}\grammarterm{constant-expression}\tcode{]} denotes +a unique dependent type. + +\pnum +If the \grammarterm{constant-expression} of a \grammarterm{pack-index-specifier} +is value-dependent, +two such \grammarterm{pack-index-specifier}s refer to the same type +only if their \grammarterm{constant-expression}s are equivalent\iref{temp.over.link}. +Otherwise, two such \grammarterm{pack-index-specifier}s refer to the same type +only if their indexes have the same value. + \rSec1[temp.decls]{Template declarations} \rSec2[temp.decls.general]{General} @@ -2743,6 +2756,12 @@ \item In a \tcode{sizeof...} expression\iref{expr.sizeof}; the pattern is an \grammarterm{identifier}. +\item In a \grammarterm{pack-index-expression}; +the pattern is an \grammarterm{identifier}. + +\item In a \grammarterm{pack-index-spexifier}; +the pattern is a \grammarterm{typedef-name}. + \item In a \grammarterm{fold-expression}\iref{expr.prim.fold}; the pattern is the \grammarterm{cast-expression} that contains an unexpanded pack. @@ -2845,6 +2864,16 @@ The instantiation of a \tcode{sizeof...} expression\iref{expr.sizeof} produces an integral constant with value $N$. +\pnum +When instantiating a \grammarterm{pack-index-expression} $P$, +let $K$ be the index of $P$. +The instantiation of P is the \grammarterm{id-expression} $E_K$. + +\pnum +When instantiating a \grammarterm{pack-index-specifier} $P$, +let $K$ be the index of $P$. +The instantiation of P is the \grammarterm{typedef-name} $E_K$. + \pnum The instantiation of an \grammarterm{alignment-specifier} with an ellipsis produces $\tcode{E}_1$ $\tcode{E}_2$ $\dotsc$ $\tcode{E}_N$. @@ -5046,7 +5075,7 @@ This includes an injected-class-name\iref{class.pre} of a class template used without a \grammarterm{template-argument-list}. \end{footnote} -or +\item a \grammarterm{pack-index-specifier}, or \item denoted by \tcode{decltype(}\grammarterm{expression}{}\tcode{)}, where \grammarterm{expression} is type-dependent\iref{temp.dep.expr}. \end{itemize} @@ -5193,6 +5222,10 @@ \pnum A \grammarterm{fold-expression} is type-dependent. +\pnum +A \grammarterm{pack-index-expression} is type-dependent +if its \grammarterm{id-expression} is type-dependent. + \rSec3[temp.dep.constexpr]{Value-dependent expressions} \pnum @@ -8132,6 +8165,8 @@ of a type that was specified using a \grammarterm{qualified-id}. \item +A \grammarterm{pack-index-specifier} or a \grammarterm{pack-index-expression}. +\item The \grammarterm{expression} of a \grammarterm{decltype-specifier}. \item A non-type template argument or an array bound in which a subexpression