diff --git a/source/compatibility.tex b/source/compatibility.tex index fd90a29804..e5b94d0967 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -96,6 +96,32 @@ \end{codeblock} \end{example} +\rSec2[diff.cpp23.temp]{\ref{temp}: templates} + +\diffref{temp.constr} +\change +Some atomic constraints become fold expanded constraints. +\rationale +Permit the subsumption of fold expressions. +\effect +Valid \CppXXIII{} code may become ill-formed. +\begin{example} +\begin{codeblock} +template struct A; +struct S { + static constexpr int compare(const S&) { return 1; } +}; + +template +void f(A *, A *) +requires (T::compare(U{}) && ...); // was well-formed (atomic constraint of type \tcode{bool}), + // now ill-formed (results in an atomic constraint of type \tcode{int}) +void g(A *ap) { + f(ap, ap); +} +\end{codeblock} +\end{example} + \rSec2[diff.cpp23.library]{\ref{library}: library introduction} \diffref{headers} diff --git a/source/templates.tex b/source/templates.tex index 23e8f391db..b88b4a7b0e 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -1480,11 +1480,12 @@ A \defn{constraint} is a sequence of logical operations and operands that specifies requirements on template arguments. The operands of a logical operation are constraints. -There are three different kinds of constraints: +There are four different kinds of constraints: \begin{itemize} \item conjunctions\iref{temp.constr.op}, -\item disjunctions\iref{temp.constr.op}, and -\item atomic constraints\iref{temp.constr.atomic}. +\item disjunctions\iref{temp.constr.op}, +\item atomic constraints\iref{temp.constr.atomic}, and +\item fold expanded constraints\iref{temp.constr.fold}. \end{itemize} \pnum @@ -1719,6 +1720,47 @@ \end{codeblock} \end{example} +\rSec3[temp.constr.fold]{Fold expanded constraint} + +\pnum +A \defnadj{fold expanded}{constraint} is formed from a constraint $C$ and +a \grammarterm{fold-operator} +which can either be \tcode{\&\&} or \tcode{||}. +A fold expanded constraint is a pack expansion\iref{temp.variadic}. +Let $N$ be the number of elements +in the pack expansion parameters\iref{temp.variadic}. + +\pnum +A fold expanded constraint whose \grammarterm{fold-operator} is \tcode{\&\&} +is satisfied if it is a valid pack expansion and +if $N = 0$ or if for each $i$ where $0 \le i < N$ in increasing order, +$C$ is satisfied +when replacing each pack expansion parameter +with the corresponding $i^\text{th}$ element. +No substitution takes place for any $i$ greater than +the smallest $i$ for which the constraint is not satisfied. + +\pnum +A fold expanded constraint whose \grammarterm{fold-operator} is \tcode{||} +is satisfied if it is a valid pack expansion, +$N > 0$, and if for $i$ where $0 \le i < N$ in increasing order, +there is a smallest $i$ for which $C$ is satisfied +when replacing each pack expansion parameter +with the corresponding $i^\text{th}$ element. +No substitution takes place for any $i$ greater than +the smallest $i$ for which the constraint is satisfied. + +\pnum +\begin{note} +If the pack expansion expands packs of different size, +then it is invalid and the fold expanded constraint is not satisfied. +\end{note} + +\pnum +Two fold expanded constraints are \defnadj{compatible for}{subsumption} +if their respective constraints both contain +an equivalent unexpanded pack\iref{temp.over.link}. + \rSec2[temp.constr.decl]{Constrained declarations} \pnum @@ -1894,6 +1936,40 @@ in the parameter mapping. \end{example} +\item +For a \grammarterm{fold-operator}\iref{expr.prim.fold} +that is either \tcode{\&\&} or \tcode{||}, +the normal form of an expression +\tcode{( ... \grammarterm{fold-operator} E )} is the normal form of +\tcode{( E \grammarterm{fold-operator} ... )}. + +\item +For a \grammarterm{fold-operator} +that is either \tcode{\&\&} or \tcode{||}, +the normal form of an expression +\tcode{( E1 \grammarterm{fold-operator} ... \grammarterm{fold-operator} E2 )} +is the the normal form of +\begin{itemize} +\item +\tcode{( E1 \grammarterm{fold-operator} ... ) \grammarterm{fold-operator} E2} +if \tcode{E1} contains an unexpanded pack, or +\item +\tcode{E1 \grammarterm{fold-operator} ( E2 \grammarterm{fold-operator} ... )} +otherwise. +\end{itemize} + +\item +The normal form of \tcode{( E \&\& ... )} is +a fold expanded constraint\iref{temp.constr.fold} +whose constraint is the normal form of \tcode{E} and +whose \grammarterm{fold-operator} is \tcode{\&\&}. + +\item +The normal form of \tcode{( E || ... )} is +a fold expanded constraint +whose constraint is the normal form of \tcode{E} and +whose \grammarterm{fold-operator} is \tcode{||}. + \item The normal form of any other expression \tcode{E} is the atomic constraint @@ -1971,11 +2047,17 @@ \item a disjunctive clause $P_i$ subsumes a conjunctive clause $Q_j$ if and only if there exists an atomic constraint $P_{ia}$ in $P_i$ for which there exists -an atomic constraint $Q_{jb}$ in $Q_j$ such that $P_{ia}$ subsumes $Q_{jb}$, and +an atomic constraint $Q_{jb}$ in $Q_j$ such that $P_{ia}$ subsumes $Q_{jb}$, \item an atomic constraint $A$ subsumes another atomic constraint $B$ if and only if $A$ and $B$ are identical using the -rules described in \ref{temp.constr.atomic}. +rules described in \ref{temp.constr.atomic}, and + +\item a fold expanded constraint $A$ subsumes +another fold expanded constraint $B$ +if they are compatible for subsumption, +have the same \grammarterm{fold-operator}, and +the constraint of $A$ subsumes that of $B$. \end{itemize} % \begin{example} @@ -2789,6 +2871,9 @@ \item In a \grammarterm{fold-expression}\iref{expr.prim.fold}; the pattern is the \grammarterm{cast-expression} that contains an unexpanded pack. + +\item In a fold expanded constraint\iref{temp.constr.fold}; +the pattern is the constraint of that fold expanded constraint. \end{itemize} \begin{example} @@ -2976,6 +3061,9 @@ \tcode{,} & \tcode{void()} \\ \end{floattable} +\pnum +A fold expanded constraint is not instantiated\iref{temp.constr.fold}. + \pnum The instantiation of any other pack expansion produces a list of elements $\tcode{E}_1, \tcode{E}_2, \dotsc, \tcode{E}_N$.