<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2024-05-21" />
  <title>Solving partial ordering issues introduced by P0522R0</title>
  <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.csl-block{margin-left: 1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      .sourceCode { overflow: visible; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

a.index:target {
display: inline;
}
.indexitems {
margin-left: 2em;
text-indent: -2em;
}
div.itemdescr {
margin-left: 3em;
}
.bnf {
font-family: serif;
margin-left: 40pt;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ncbnf {
font-family: serif;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
}
.ncsimplebnf {
font-family: serif;
font-style: italic;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
background: inherit;
}
span.textnormal {
font-style: normal;
font-family: serif;
white-space: normal;
display: inline-block;
}
span.rlap {
display: inline-block;
width: 0px;
}
span.descr { font-style: normal; font-family: serif; }
span.grammarterm { font-style: italic; }
span.term { font-style: italic; }
span.terminal { font-family: monospace; font-style: normal; }
span.nonterminal { font-style: italic; }
span.tcode { font-family: monospace; font-style: normal; }
span.textbf { font-weight: bold; }
span.textsc { font-variant: small-caps; }
a.nontermdef { font-style: italic; font-family: serif; }
span.emph { font-style: italic; }
span.techterm { font-style: italic; }
span.mathit { font-style: italic; }
span.mathsf { font-family: sans-serif; }
span.mathrm { font-family: serif; font-style: normal; }
span.textrm { font-family: serif; }
span.textsl { font-style: italic; }
span.mathtt { font-family: monospace; font-style: normal; }
span.mbox { font-family: serif; font-style: normal; }
span.ungap { display: inline-block; width: 2pt; }
span.textit { font-style: italic; }
span.texttt { font-family: monospace; }
span.tcode_in_codeblock { font-family: monospace; font-style: normal; }
span.phantom { color: white; }

span.math { font-style: normal; }
span.mathblock {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 1.2em;
margin-bottom: 1.2em;
text-align: center;
}
span.mathalpha {
font-style: italic;
}
span.synopsis {
font-weight: bold;
margin-top: 0.5em;
display: block;
}
span.definition {
font-weight: bold;
display: block;
}
.codeblock {
margin-left: 1.2em;
line-height: 127%;
}
.outputblock {
margin-left: 1.2em;
line-height: 127%;
}
div.itemdecl {
margin-top: 2ex;
}
code.itemdeclcode {
white-space: pre;
display: block;
}
span.textsuperscript {
vertical-align: super;
font-size: smaller;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: smaller; line-height: 0; }
.footnote {
font-size: small;
margin-left: 2em;
margin-right: 2em;
margin-top: 0.6em;
margin-bottom: 0.6em;
}
div.minipage {
display: inline-block;
margin-right: 3em;
}
div.numberedTable {
text-align: center;
margin: 2em;
}
div.figure {
text-align: center;
margin: 2em;
}
table {
border: 1px solid black;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
margin-top: 0.8em;
text-align: left;
hyphens: none;
}
td, th {
padding-left: 1em;
padding-right: 1em;
vertical-align: top;
}
td.empty {
padding: 0px;
padding-left: 1px;
}
td.left {
text-align: left;
}
td.right {
text-align: right;
}
td.center {
text-align: center;
}
td.justify {
text-align: justify;
}
td.border {
border-left: 1px solid black;
}
tr.rowsep, td.cline {
border-top: 1px solid black;
}
tr.even, tr.odd {
border-bottom: 1px solid black;
}
tr.capsep {
border-top: 3px solid black;
border-top-style: double;
}
tr.header {
border-bottom: 3px solid black;
border-bottom-style: double;
}
th {
border-bottom: 1px solid black;
}
span.centry {
font-weight: bold;
}
div.table {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
width: 90%;
}
span.indented {
display: block;
margin-left: 2em;
margin-bottom: 1em;
margin-top: 1em;
}
ol.enumeratea { list-style-type: none; background: inherit; }
ol.enumerate { list-style-type: none; background: inherit; }

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />

  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">Solving partial ordering
issues introduced by P0522R0</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3310R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-05-21</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      EWG, CWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Matheus Izvekov<br>&lt;<a href="mailto:mizvekov@gmail.com" class="email">mizvekov@gmail.com</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">1</span> Introduction<span></span></a></li>
<li><a href="#problem-1---default-arguments" id="toc-problem-1---default-arguments"><span class="toc-section-number">2</span> Problem #1 - Default
Arguments<span></span></a>
<ul>
<li><a href="#solution-to-1" id="toc-solution-to-1"><span class="toc-section-number">2.1</span> Solution to
#1<span></span></a></li>
<li><a href="#wording-for-1" id="toc-wording-for-1"><span class="toc-section-number">2.2</span> Wording for
#1<span></span></a></li>
</ul></li>
<li><a href="#problem-2---with-vs-without-packs" id="toc-problem-2---with-vs-without-packs"><span class="toc-section-number">3</span> Problem #2 - With vs Without
Packs<span></span></a>
<ul>
<li><a href="#solution-to-2" id="toc-solution-to-2"><span class="toc-section-number">3.1</span> Solution to
#2<span></span></a></li>
<li><a href="#wording-to-2" id="toc-wording-to-2"><span class="toc-section-number">3.2</span> Wording to
#2<span></span></a></li>
</ul></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">4</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="introduction"><span class="header-section-number">1</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>This paper aims to address some lingering issues introduced with the
adoption of P0522R0 into C++17, later made a defect report, which
relaxed the rules on how templates are matched to template template
parameters, but didn’t concern itself with how partial ordering would be
affected.</p>
<p>As a result, it invalidated several perfectly legitimate prior uses,
creating compatibility issues with old code, forcing implementors to
amend the rules, and overall slowing adoption.</p>
<p>We will point out two separate issues and their proposed solutions,
which can be picked and voted independently, with the intention that
they be adopted as resolutions to <span class="citation" data-cites="CWG2398">[<a href="https://wg21.link/cwg2398" role="doc-biblioref">CWG2398</a>]</span>, which is the core issue
tracking this problem.</p>
<p>The intent is to keep old code working, not to change best practices.
With that said, these proposed rules should keep things more consistent
and explainable, as candidates having template template parameters with
more non-pack parameters will be more specialized than those with fewer,
and those taking pack parameters will be less specialized than those
than don’t.</p>
<p>If any of the solutions is adopted, it is suggested to bump the
version for the feature testing macro.</p>
<h1 data-number="2" id="problem-1---default-arguments"><span class="header-section-number">2</span> Problem #1 - Default Arguments<a href="#problem-1---default-arguments" class="self-link"></a></h1>
<p>Consider the following example:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T1<span class="op">&gt;</span> <span class="kw">struct</span> A<span class="op">;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T2<span class="op">&gt;</span> <span class="kw">class</span> TT1<span class="op">,</span> <span class="kw">class</span> T3<span class="op">&gt;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> A<span class="op">&lt;</span>TT1<span class="op">&lt;</span>T3<span class="op">&gt;&gt;;</span> <span class="co">// #1</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T4<span class="op">,</span> <span class="kw">class</span> T5<span class="op">&gt;</span> <span class="kw">class</span> TT2<span class="op">,</span> <span class="kw">class</span> T6<span class="op">,</span> <span class="kw">class</span> T7<span class="op">&gt;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> A<span class="op">&lt;</span>TT2<span class="op">&lt;</span>T6<span class="op">,</span> T7<span class="op">&gt;&gt;</span> <span class="op">{};</span> <span class="co">// #2</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T8<span class="op">,</span> <span class="kw">class</span> T9 <span class="op">=</span> <span class="dt">float</span><span class="op">&gt;</span> <span class="kw">struct</span> B<span class="op">;</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="kw">struct</span> A<span class="op">&lt;</span>B<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;;</span></span></code></pre></div>
<p>Prior to <span class="citation" data-cites="P0522R0">[<a href="https://wg21.link/p0522r0" role="doc-biblioref">P0522R0</a>]</span>, with the more strict rules,
only the partial specialization candidate
<code class="sourceCode cpp"><span class="pp">#2</span></code> would be
considered, since <code class="sourceCode cpp">B</code> has two template
parameters, <code class="sourceCode cpp">T8</code> and
<code class="sourceCode cpp">T9</code>, and the template template
parameter in
<code class="sourceCode cpp"><span class="pp">#1</span></code> has only
<code class="sourceCode cpp">T2</code> as a template parameter, so
<code class="sourceCode cpp"><span class="pp">#1</span></code> doesn’t
match.</p>
<p>After P0522R0,
<code class="sourceCode cpp"><span class="pp">#1</span></code> starts
being accepted as a candidate, since
<code class="sourceCode cpp">B</code> can be used just fine in place of
<code class="sourceCode cpp">TT1</code> in the specialization <code class="sourceCode cpp">A<span class="op">&lt;</span>TT1<span class="op">&lt;</span>T3<span class="op">&gt;&gt;</span></code>:
The default argument
<code class="sourceCode cpp"><span class="dt">float</span></code> for
<code class="sourceCode cpp">T9</code> allows
<code class="sourceCode cpp">B</code> to be specialized with just a
single argument.</p>
<p>However, the rules for partial ordering operate considering only the
candidates themselves, without access to
<code class="sourceCode cpp">B</code>, which has the default template
argument. When looking at only those candidates, it’s not obvious the
specialization of <code class="sourceCode cpp">TT1</code> would work, if
that were to be replaced with a template with two parameters.</p>
<p>The only clue is the fact that these two candidates are being
considered together: this must mean that default arguments are somehow
involved.</p>
<p>But nonetheless, as things stand, these candidates cannot be ordered,
resulting in ambiguity.</p>
<p>Maintaining the pre-P0522 semantics of picking
<code class="sourceCode cpp"><span class="pp">#2</span></code> would be
ideal: Besides that it would be a compatible change, it is logical that
this is the most specialized candidate.</p>
<h2 data-number="2.1" id="solution-to-1"><span class="header-section-number">2.1</span> Solution to #1<a href="#solution-to-1" class="self-link"></a></h2>
<p>When performing template argument deduction such that
<code class="sourceCode cpp">P</code> and
<code class="sourceCode cpp">A</code> are specializations of either
class templates or template template parameters:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>P = TT1&lt;X1, ..., Xn&gt;</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>A = TT2&lt;Y1, ..., Yn&gt;</span></code></pre></div>
<p>Under the current rules, <code class="sourceCode cpp">TT1</code> will
be deduced as <code class="sourceCode cpp">TT2</code>.</p>
<p>This paper proposes that in this case,
<code class="sourceCode cpp">TT1</code> will be deduced as a new
template, synthesized from and almost identical to
<code class="sourceCode cpp">TT2</code>, except that the specialization
arguments
(<code class="sourceCode cpp">Y1, <span class="op">...</span>, Yn</code>)
will be used as default arguments in this new invented TT2, replacing
any existing ones, effectively as if it had been written as:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T1 <span class="op">=</span> Y1<span class="op">,</span> <span class="op">...,</span> <span class="kw">class</span> Tn <span class="op">=</span> Yn<span class="op">&gt;</span> <span class="kw">class</span> TT2</span></code></pre></div>
<p>Conversely, a template template parameter can also be deduced as a
class template:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T1<span class="op">,</span> <span class="kw">class</span> T2 <span class="op">=</span> <span class="dt">float</span><span class="op">&gt;</span> <span class="kw">struct</span> A<span class="op">;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T3<span class="op">&gt;</span> <span class="kw">struct</span> B<span class="op">;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T4<span class="op">&gt;</span> <span class="kw">class</span> TT1<span class="op">,</span> <span class="kw">class</span> T5<span class="op">&gt;</span> <span class="kw">struct</span> B<span class="op">&lt;</span>TT1<span class="op">&lt;</span>T5<span class="op">&gt;&gt;;</span>   <span class="co">// #1</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T6<span class="op">,</span> <span class="kw">class</span> T7<span class="op">&gt;</span>                      <span class="kw">struct</span> B<span class="op">&lt;</span>A<span class="op">&lt;</span>T6<span class="op">,</span> T7<span class="op">&gt;&gt;;</span> <span class="co">// #2</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="kw">struct</span> B<span class="op">&lt;</span>A<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;;</span></span></code></pre></div>
<p>When partially ordering
<code class="sourceCode cpp"><span class="pp">#1</span></code> versus
<code class="sourceCode cpp"><span class="pp">#2</span></code>, TT1 will
be deduced as a synthesized template re-declaration of A with <code class="sourceCode cpp"><span class="op">&lt;</span>T6, T7<span class="op">&gt;</span></code>
as default arguments.</p>
<p>When these proposed rules are applied to class template deduction,
this example, which is unrelated to partial ordering, also becomes
valid:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">,</span> <span class="kw">class</span> U<span class="op">&gt;</span> <span class="kw">struct</span> A <span class="op">{};</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>A<span class="op">&lt;</span><span class="dt">int</span><span class="op">,</span> <span class="dt">float</span><span class="op">&gt;</span> v<span class="op">;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">&gt;</span> <span class="kw">class</span> TT<span class="op">&gt;</span> <span class="dt">void</span> f<span class="op">(</span>TT<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;);</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> g<span class="op">()</span> <span class="op">{</span> f<span class="op">(</span>v<span class="op">);</span> <span class="op">}</span></span></code></pre></div>
<p>Here, ‘TT’ picks a synthesized re-declaration of ‘A’ which has
‘float’ as the default argument for the second parameter.</p>
<p>When a parameter is deduced against multiple arguments, consistency
must be enforced.</p>
<p>Given this example:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span> <span class="kw">struct</span> N <span class="op">{</span> <span class="kw">using</span> type <span class="op">=</span> T<span class="op">;</span> <span class="op">};</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T1<span class="op">,</span> <span class="kw">class</span> T2<span class="op">,</span> <span class="kw">class</span> T3<span class="op">&gt;</span> <span class="kw">struct</span> A<span class="op">;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">,</span> <span class="kw">class</span><span class="op">&gt;</span> <span class="kw">class</span> TT1<span class="op">,</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> T1<span class="op">,</span> <span class="kw">class</span> T2<span class="op">,</span> <span class="kw">class</span> T3<span class="op">,</span> <span class="kw">class</span> T4<span class="op">&gt;</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> A<span class="op">&lt;</span>TT1<span class="op">&lt;</span>T1<span class="op">,</span> T2<span class="op">&gt;,</span> TT1<span class="op">&lt;</span>T3<span class="op">,</span> T4<span class="op">&gt;,</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>         <span class="kw">typename</span> N<span class="op">&lt;</span>TT1<span class="op">&lt;</span>T1<span class="op">,</span> T2<span class="op">&gt;&gt;::</span>type<span class="op">&gt;</span> <span class="op">{};</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">&gt;</span> <span class="kw">class</span> UU1<span class="op">,</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>         <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">&gt;</span> <span class="kw">class</span> UU2<span class="op">,</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> U1<span class="op">,</span> <span class="kw">class</span> U2<span class="op">&gt;</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> A<span class="op">&lt;</span>UU1<span class="op">&lt;</span>U1<span class="op">&gt;,</span> UU2<span class="op">&lt;</span>U2<span class="op">&gt;,</span> <span class="kw">typename</span> N<span class="op">&lt;</span>UU1<span class="op">&lt;</span>U1<span class="op">&gt;&gt;::</span>type<span class="op">&gt;;</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T8<span class="op">,</span> <span class="kw">class</span> T9 <span class="op">=</span> <span class="dt">float</span><span class="op">&gt;</span> <span class="kw">struct</span> B<span class="op">;</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="kw">struct</span> A<span class="op">&lt;</span>B<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;,</span> B<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;,</span> B<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;;</span></span></code></pre></div>
<p>This was accepted prior to P0522R0, but picking <code class="sourceCode cpp"><span class="op">&lt;</span>T1, T2<span class="op">&gt;</span></code>
for the default arguments of <code class="sourceCode cpp">TT1</code>
will result in this example being accepted, but result in rejection of
the symmetric example where <code class="sourceCode cpp">N<span class="op">&lt;</span>TT1<span class="op">&lt;</span>T1, T2<span class="op">&gt;&gt;</span></code>
is replaced with <code class="sourceCode cpp">N<span class="op">&lt;</span>TT1<span class="op">&lt;</span>T1, T4<span class="op">&gt;&gt;</span></code>,
which is also accepted pre-P0522.</p>
<p>There is no known mechanically simple and sound way to solve this. It
would not be simple, but sound, if the solution were to include a
mechanism to deduce that T2 and T4 must be the same type. Unless there
is sufficient motivation to try to salvage this situation, it’s proposed
that both forms be rejected, for consistency.</p>
<p>To achieve this consistency, multiple deductions must be combined by
stripping out differing default arguments.</p>
<h2 data-number="2.2" id="wording-for-1"><span class="header-section-number">2.2</span> Wording for #1<a href="#wording-for-1" class="self-link"></a></h2>
<p>Modify §13.10.3.6 <span>13.10.3.6
<a href="https://wg21.link/temp.deduct.type">[temp.deduct.type]</a></span>/8:</p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
A template type argument T, a template template argument TT, or a
template non-type argument i can be deduced if P and A have one of the
following forms:</p>
<div class="line-block">cv<sub>opt</sub> T<br />
T*<br />
T&amp;<br />
T&amp;&amp;<br />
T<sub>opt</sub> [i<sub>opt</sub>]<br />
T<sub>opt</sub> (T<sub>opt</sub>) noexcept(i<sub>opt</sub>)<br />
T<sub>opt</sub> T<sub>opt</sub>::*<br />
TT<sub>opt</sub>&lt;T&gt;<br />
TT<sub>opt</sub>&lt;i&gt;<br />
TT<sub>opt</sub>&lt;TT<sub><span class="add" style="color: #006e28"><ins>opt</ins></span></sub>&gt;<br />
TT<sub>opt</sub>&lt;&gt;</div>
<div class="add" style="color: #006e28">

<div class="line-block">TT<sub>opt</sub></div>

</div>
<p><span class="marginalizedparent"><a class="marginalized">(8.1)</a></span> -
T<sub>opt</sub> represents a type or parameter-type-list that either
satisfies these rules recursively, is a non-deduced context in P or A,
or is the same non-dependent type in P and A,</p>
<p><span class="marginalizedparent"><a class="marginalized">(8.2)</a></span> -
TT<sub>opt</sub> represents either a class template or a template
template parameter,</p>
<div class="add" style="color: #006e28">
<p>[Example:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode default c++"><code class="sourceCode default"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>template&lt;class T, class U&gt; struct A {};</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>template&lt;template&lt;class&gt; class TT&gt; void f(TT&lt;int&gt;);</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>void g() {</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  A&lt;int, float&gt; v;</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  // OK, TT = A, &#39;float&#39; is used as default argument the second parameter</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  f(v);</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<ul>
<li>end example]</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">(8.3)</a></span> -
When matching TT<sub>opt</sub> specializations, TT<sub>opt</sub> will be
deduced as if it’s template argument list in A were used as the default
arguments for it’s template parameters, up to the last parameter which
has a corresponding argument. When multiple such arguments are deduced,
only default arguments which are common to all deductions are kept.</p>
</div>
<p>Append examples to §13.4.4 <span>13.4.4
<a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>/4:</p>
<div class="add" style="color: #006e28">
<p>[Example:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode default c++"><code class="sourceCode default"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>template &lt;class, class = float&gt; struct A;</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>template &lt;class&gt; struct B;</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class&gt; class TT, class T&gt; struct B&lt;TT&lt;T&gt;&gt;;   // #1</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>template &lt;class T, class U&gt;                   struct B&lt;A&lt;T, U&gt;&gt;; // #2</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>template struct B&lt;A&lt;int&gt;&gt;; // selects #2</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>template &lt;class&gt; struct C;</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class&gt; class TT, class T&gt; struct C&lt;TT&lt;T&gt;&gt;;   // #3</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>template &lt;class T, class U&gt;                   struct C&lt;A&lt;T, U&gt;&gt;; // #4</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>template struct C&lt;A&lt;int&gt;&gt;; // selects #4</span></code></pre></div>
<ul>
<li>end example]</li>
</ul>
<p>[Example:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode default c++"><code class="sourceCode default"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; struct N { using type = T; };</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>template&lt;class, class = float&gt; struct A;</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>template&lt;class, class, class&gt; struct B;</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>template&lt;template&lt;class, class&gt; class TT,</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>         class T1, class T2, class T3, class T4&gt;</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>struct B&lt;TT&lt;T1, T2&gt;, TT&lt;T3, T4&gt;,</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>         typename N&lt;TT&lt;T1, T2&gt;&gt;::type&gt;;</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>template&lt;template&lt;class&gt; class UU1,</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>         template&lt;class&gt; class UU2,</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>         class U1, class U2&gt;</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>struct B&lt;UU1&lt;U1&gt;, UU2&lt;U2&gt;, typename N&lt;UU1&lt;U1&gt;&gt;::type&gt;;</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>template struct B&lt;A&lt;int&gt;, A&lt;int&gt;, A&lt;int&gt;&gt;; // ambiguous</span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a>template&lt;class, class, class&gt; struct C;</span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a>template&lt;template&lt;class, class&gt; class TT,</span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a>         class T1, class T2, class T3, class T4&gt;</span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a>struct C&lt;TT&lt;T1, T2&gt;, TT&lt;T3, T4&gt;,</span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a>         typename N&lt;TT&lt;T1, T4&gt;&gt;::type&gt;;</span>
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a>template&lt;template&lt;class&gt; class UU1,</span>
<span id="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></a>         template&lt;class&gt; class UU2,</span>
<span id="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a>         class U1, class U2&gt;</span>
<span id="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a>struct C&lt;UU1&lt;U1&gt;, UU2&lt;U2&gt;, typename N&lt;UU1&lt;U1&gt;&gt;::type&gt;;</span>
<span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a>template struct C&lt;A&lt;int&gt;, A&lt;int&gt;, A&lt;int&gt;&gt;; // ambiguous</span></code></pre></div>
<ul>
<li>end example]</li>
</ul>

</div>
<p>Modify example in §13.7.8 <span>13.7.8
<a href="https://wg21.link/temp.alias">[temp.alias]</a></span>/2:</p>
<p>[Example 1:</p>
<div>
<div class="sourceCode" id="cb5"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="dt">-13,7 +13,8</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> template&lt;template&lt;class&gt; class TT&gt;</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>   void f(TT&lt;int&gt;);</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="st">-f(v);               // error: Vec not deduced</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="va">+// OK, TT = vector, Alloc&lt;int&gt; used as default argument for second parameter</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="va">+f(v);</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a> template&lt;template&lt;class,class&gt; class TT&gt;</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>   void g(TT&lt;int, Alloc&lt;int&gt;&gt;);</span></code></pre></div>
</div>
<p>— end example]</p>
<h1 data-number="3" id="problem-2---with-vs-without-packs"><span class="header-section-number">3</span> Problem #2 - With vs Without
Packs<a href="#problem-2---with-vs-without-packs" class="self-link"></a></h1>
<p>Consider the following example:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> <span class="op">...</span>T1s<span class="op">&gt;</span> <span class="kw">class</span> TT1<span class="op">&gt;</span> <span class="kw">struct</span> A <span class="op">{};</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T2<span class="op">&gt;</span> <span class="kw">struct</span> B<span class="op">;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="kw">struct</span> A<span class="op">&lt;</span>B<span class="op">&gt;;</span> <span class="co">// #1</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T3<span class="op">&gt;</span> <span class="kw">class</span> TT2<span class="op">&gt;</span> <span class="kw">struct</span> C <span class="op">{};</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> <span class="op">...</span>T4s<span class="op">&gt;</span> <span class="kw">struct</span> D<span class="op">;</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="kw">struct</span> C<span class="op">&lt;</span>D<span class="op">&gt;;</span> <span class="co">// #2</span></span></code></pre></div>
<p>Before <span class="citation" data-cites="P0522R0">[<a href="https://wg21.link/p0522r0" role="doc-biblioref">P0522R0</a>]</span>,
<code class="sourceCode cpp"><span class="pp">#1</span></code> was
valid, and
<code class="sourceCode cpp"><span class="pp">#2</span></code> was
invalid.</p>
<p>After P0522R0,
<code class="sourceCode cpp"><span class="pp">#1</span></code> stayed
valid, and
<code class="sourceCode cpp"><span class="pp">#2</span></code> became
valid.</p>
<p>Now consider this partial ordering example:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T1<span class="op">&gt;</span> <span class="kw">struct</span> A<span class="op">;</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> <span class="op">...</span>T2s<span class="op">&gt;</span> <span class="kw">class</span> TT1<span class="op">,</span> <span class="kw">class</span> T3<span class="op">&gt;</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> A<span class="op">&lt;</span>TT1<span class="op">&lt;</span>T3<span class="op">&gt;&gt;;</span> <span class="co">// #1</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T4<span class="op">&gt;</span> <span class="kw">class</span> TT2<span class="op">,</span> <span class="kw">class</span> T5<span class="op">&gt;</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> A<span class="op">&lt;</span>TT2<span class="op">&lt;</span>T5<span class="op">&gt;&gt;</span> <span class="op">{};</span> <span class="co">// #2</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T6<span class="op">&gt;</span> <span class="kw">struct</span> B<span class="op">;</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="kw">struct</span> A<span class="op">&lt;</span>B<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;;</span></span></code></pre></div>
<p>Before P0522R0,
<code class="sourceCode cpp"><span class="pp">#2</span></code> was
picked.</p>
<p>However, since the same rules which determine a template can bind to
a template template parameter, are also used to determine one template
template parameter is at least as specialized as another, and since
P0522R0 made no special provisions in these rules for the latter, this
example now becomes ambiguous.</p>
<p>But this is undesirable, because it is a breaking change, and also
because logically
<code class="sourceCode cpp"><span class="pp">#2</span></code> is more
specialized.</p>
<p>The new paragraph inserted with P0522R0, which defines the ‘at least
as specialized as’ rules in terms of function template rewrite, leads to
this confusion:</p>
<p>The template argument list deduction rules accept packs in parameters
and no packs in arguments, while the reverse is rejected, but in order
to accept both
<code class="sourceCode cpp"><span class="pp">#1</span></code> and
<code class="sourceCode cpp"><span class="pp">#2</span></code> from the
first example, both directions need to be accepted. An exception had to
be carved out in <span>13.4.4
<a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>/3
for this.</p>
<p>We propose a solution which will restore the semantics of the second
example, by specifying that during partial ordering, packs must match
non-packs in only one direction.</p>
<p>Now consider this last example:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span>    <span class="op">&gt;</span> <span class="kw">class</span> TT1<span class="op">&gt;</span> <span class="kw">struct</span> A      <span class="op">{</span> <span class="at">static</span> <span class="kw">constexpr</span> <span class="dt">int</span> V <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="op">};</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span>       <span class="op">&gt;</span> <span class="kw">class</span> TT2<span class="op">&gt;</span> <span class="kw">struct</span> A<span class="op">&lt;</span>TT2<span class="op">&gt;</span> <span class="op">{</span> <span class="at">static</span> <span class="kw">constexpr</span> <span class="dt">int</span> V <span class="op">=</span> <span class="dv">1</span><span class="op">;</span> <span class="op">};</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">,</span> <span class="kw">class</span><span class="op">&gt;</span> <span class="kw">class</span> TT3<span class="op">&gt;</span> <span class="kw">struct</span> A<span class="op">&lt;</span>TT3<span class="op">&gt;</span> <span class="op">{</span> <span class="at">static</span> <span class="kw">constexpr</span> <span class="dt">int</span> V <span class="op">=</span> <span class="dv">2</span><span class="op">;</span> <span class="op">};</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> <span class="op">...</span>          <span class="op">&gt;</span> <span class="kw">struct</span> B<span class="op">;</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span>              <span class="op">&gt;</span> <span class="kw">struct</span> C<span class="op">;</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">,</span> <span class="kw">class</span>       <span class="op">&gt;</span> <span class="kw">struct</span> D<span class="op">;</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">,</span> <span class="kw">class</span><span class="op">,</span> <span class="kw">class</span><span class="op">&gt;</span> <span class="kw">struct</span> E<span class="op">;</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>A<span class="op">&lt;</span>B<span class="op">&gt;::</span>V <span class="op">==</span> <span class="dv">0</span><span class="op">);</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>A<span class="op">&lt;</span>C<span class="op">&gt;::</span>V <span class="op">==</span> <span class="dv">1</span><span class="op">);</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>A<span class="op">&lt;</span>D<span class="op">&gt;::</span>V <span class="op">==</span> <span class="dv">2</span><span class="op">);</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>A<span class="op">&lt;</span>E<span class="op">&gt;::</span>V <span class="op">==</span> <span class="dv">0</span><span class="op">);</span></span></code></pre></div>
<p>Before P0522R0, this is accepted.</p>
<p>After P0522R0, this became wholly invalid: The partial
specializations are not more specialized than the primary template.
Also, the <code class="sourceCode cpp">A<span class="op">&lt;</span>B<span class="op">&gt;</span></code>
specialization becomes ambiguous.</p>
<p>With the proposed solution, the primary template becomes less
specialized again.</p>
<p>But the other issue will remain: The <code class="sourceCode cpp">A<span class="op">&lt;</span>B<span class="op">&gt;</span></code>
specialization will stay ambiguous. A solution to this last problem is
left for future work.</p>
<h2 data-number="3.1" id="solution-to-2"><span class="header-section-number">3.1</span> Solution to #2<a href="#solution-to-2" class="self-link"></a></h2>
<p>We propose changing the deduction rules such that, only during
partial ordering, packs matching to non-packs isn’t accepted both ways,
that it should only be accepted in the argument to parameter direction,
which is the opposite direction it’s normally accepted in the deduction
of template argument lists.</p>
<p>We also propose scratching the classic pack exception clause in
[temp.arg.template]/3{.sref}, in favor of explicitly specifying that
outside of partial ordering, packs matching to non-packs must be
accepted both ways, parameter to argument as well as argument to
parameter.</p>
<h2 data-number="3.2" id="wording-to-2"><span class="header-section-number">3.2</span> Wording to #2<a href="#wording-to-2" class="self-link"></a></h2>
<p>Modify §13.10.3.6 <span>13.10.3.6
<a href="https://wg21.link/temp.deduct.type">[temp.deduct.type]</a></span>/9:</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
If P has a form that contains &lt;T&gt;<span class="rm" style="color: #bf0303"><del>or</del></span><span class="add" style="color: #006e28"><ins>,</ins></span> &lt;i&gt;, <span class="add" style="color: #006e28"><ins>or &lt;TT<sub>opt</sub>&gt;,</ins></span>
then each argument P<sub>i</sub> of the respective template argument
list of P is compared with the corresponding argument A<sub>i</sub> of
the corresponding template argument list of A. If the template argument
list of P contains a pack expansion that is not the last template
argument, the entire template argument list is a non-deduced context.
<span class="rm" style="color: #bf0303"><del>If P<sub>i</sub> is a pack
expansion, then the pattern of P<sub>i</sub> is compared with each
remaining argument in the template argument list of A. Each comparison
deduces template arguments for subsequent positions in the template
parameter packs expanded by P<sub>i</sub>. During partial ordering, if
A<sub>i</sub> was originally a pack expansion:</del></span></p>
<div class="rm" style="color: #bf0303">
<p><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span> - if
P does not contain a template argument corresponding to A<sub>i</sub>
then A<sub>i</sub> is ignored;</p>
<p><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span> -
otherwise, if P<sub>i</sub> is not a pack expansion, template argument
deduction fails.</p>
</div>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span>
<span class="add" style="color: #006e28"><ins>Except when deducing the
argument list of X as specified in <span>13.4.4
<a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>/4,
while checking deduced template arguments,</ins></span> if P<sub>i</sub>
is a pack expansion, then the pattern of P<sub>i</sub> is compared with
each remaining argument in the template argument list of A. Each
comparison deduces template arguments for subsequent positions in the
template parameter packs expanded by P<sub>i</sub>. During partial
ordering, if A<sub>i</sub> was originally a pack expansion:</p>
<p><span class="marginalizedparent"><a class="marginalized">(9.1.1)</a></span> -
if P does not contain a template argument corresponding to A<sub>i</sub>
then A<sub>i</sub> is ignored;</p>
<p><span class="marginalizedparent"><a class="marginalized">(9.1.2)</a></span> -
otherwise, if P<sub>i</sub> is not a pack expansion, template argument
deduction fails.</p>
<p><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span>
<span class="add" style="color: #006e28"><ins>When deducing the argument
list of X as specified in <span>13.4.4
<a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>/4,
if A<sub>i</sub> is a pack expansion, then the pattern of A<sub>i</sub>
is compared with each remaining argument in the template argument list
of P. Each comparison deduces template arguments for subsequent
positions in the template parameter packs expanded by A<sub>i</sub>. If
P<sub>i</sub> was originally a pack expansion:</ins></span></p>
<p><span class="marginalizedparent"><a class="marginalized">(9.2.1)</a></span> -
<span class="add" style="color: #006e28"><ins>if A does not contain a
template argument corresponding to P<sub>i</sub> then P<sub>i</sub> is
ignored;</ins></span></p>
<p><span class="marginalizedparent"><a class="marginalized">(9.2.2)</a></span> -
<span class="add" style="color: #006e28"><ins>otherwise, if
A<sub>i</sub> is not a pack expansion, template argument deduction
fails.</ins></span></p>
<p>[Note: (9.2) is the reverse of (9.1) - end note]</p>
</div>
<p>Modify §13.4.4 <span>13.4.4
<a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>/3:</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
A template-argument matches a template template-parameter P when P is at
least as specialized as the template-argument A. In this comparison, if
P is unconstrained, the constraints on A are not considered. <span class="rm" style="color: #bf0303"><del>If P contains a template
parameter pack, then A also matches P if each of A’s template parameters
matches the corresponding template parameter in the template-head of
P</del></span>. Two template parameters match if they are of the same
kind (type, non-type, template), for non-type template-parameters, their
types are equivalent (<span>13.7.7.2
<a href="https://wg21.link/temp.over.link">[temp.over.link]</a></span>),
and for template template-parameters, each of their corresponding
template-parameters matches, recursively. When P’s template-head
contains a template parameter pack (<span>13.7.4
<a href="https://wg21.link/temp.variadic">[temp.variadic]</a></span>),
the template parameter pack will match zero or more template parameters
or template parameter packs in the template-head of A with the same type
and form as the template parameter pack in P (ignoring whether those
template parameters are template parameter packs).</p>
<p>Append note and example to §13.4.4 <span>13.4.4
<a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>/4:</p>
<div class="add" style="color: #006e28">
<p>[Note: <span>13.10.3.6
<a href="https://wg21.link/temp.deduct.type">[temp.deduct.type]</a></span>/9
has a special case for this deduction - end note]</p>
<p>[Example:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode default c++"><code class="sourceCode default"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>template&lt;class T1&gt; struct A;</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>template&lt;template&lt;class ...&gt; class TT, class T&gt; struct A&lt;TT&lt;T&gt;&gt;; // #1</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>template&lt;template&lt;class    &gt; class TT, class T&gt; struct A&lt;TT&lt;T&gt;&gt;; // #2</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>template&lt;class&gt; struct B;</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>template struct A&lt;B&lt;int&gt;&gt;; // selects #2</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class...&gt; class TT&gt; struct C;</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>// This partial specialization is more specialized than the primary template.</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class&gt; class TT&gt; struct C&lt;TT&gt;;</span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class&gt; class TT&gt; struct D;</span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>// This partial specialization is NOT more specialized than the primary template.</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class...&gt; class TT&gt; struct D&lt;TT&gt;;</span></code></pre></div>
<ul>
<li>end example]</li>
</ul>

</div>
<h1 data-number="4" id="bibliography"><span class="header-section-number">4</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-CWG2398" class="csl-entry" role="doc-biblioentry">
[CWG2398] Jason Merrill. 2016-12-03. Template template parameter
matching and deduction. <a href="https://wg21.link/cwg2398"><div class="csl-block">https://wg21.link/cwg2398</div></a>
</div>
<div id="ref-P0522R0" class="csl-entry" role="doc-biblioentry">
[P0522R0] James Touton, Hubert Tong. 2016-11-11. DR: Matching of
template template-arguments excludes compatible templates. <a href="https://wg21.link/p0522r0"><div class="csl-block">https://wg21.link/p0522r0</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
