<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<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="2025-05-18" />
  <title>Solving issues introduced by relaxed template template
parameter matching</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 issues introduced by
relaxed template template parameter matching</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>
      P3310R6
      [<a href="https://wg21.link/P3310">Latest</a>]
      [<a href="https://wg21.link/P3310/status">Status</a>]
    </td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-05-18</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>
      Evolution Working Group<br>
      Core Working Group<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>
      James Touton<br>&lt;<a href="mailto:bekenn@gmail.com" class="email">bekenn@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="#changelog" id="toc-changelog"><span class="toc-section-number">2</span> Changelog<span></span></a>
<ul>
<li><a href="#since-r5" id="toc-since-r5"><span class="toc-section-number">2.0.1</span> Since R5<span></span></a></li>
<li><a href="#since-r4" id="toc-since-r4"><span class="toc-section-number">2.0.2</span> Since R4<span></span></a></li>
<li><a href="#since-r3" id="toc-since-r3"><span class="toc-section-number">2.0.3</span> Since R3<span></span></a></li>
<li><a href="#since-r2" id="toc-since-r2"><span class="toc-section-number">2.0.4</span> Since R2<span></span></a></li>
<li><a href="#since-r1" id="toc-since-r1"><span class="toc-section-number">2.0.5</span> Since R1<span></span></a></li>
<li><a href="#since-r0" id="toc-since-r0"><span class="toc-section-number">2.0.6</span> Since R0<span></span></a></li>
</ul></li>
<li><a href="#problem-1---default-arguments" id="toc-problem-1---default-arguments"><span class="toc-section-number">3</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">3.1</span> Solution to #1<span></span></a>
<ul>
<li><a href="#class-templates" id="toc-class-templates"><span class="toc-section-number">3.1.1</span> Class
templates<span></span></a></li>
<li><a href="#consistency" id="toc-consistency"><span class="toc-section-number">3.1.2</span>
Consistency<span></span></a></li>
<li><a href="#packs" id="toc-packs"><span class="toc-section-number">3.1.3</span> Packs<span></span></a></li>
</ul></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">4</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">4.1</span> Solution to
#2<span></span></a></li>
</ul></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">5</span> Wording<span></span></a></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">6</span>
Acknowledgements<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">7</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 <span class="citation" data-cites="P0522R0"><a href="https://wg21.link/p0522r0" role="doc-biblioref">[P0522R0]</a></span> 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 and overload resolution 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,
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>It is also suggested to bump the version for the feature testing
macro.</p>
<h1 data-number="2" id="changelog"><span class="header-section-number">2</span> Changelog<a href="#changelog" class="self-link"></a></h1>
<h3 data-number="2.0.1" id="since-r5"><span class="header-section-number">2.0.1</span> Since R5<a href="#since-r5" class="self-link"></a></h3>
<ul>
<li>Wording changes.</li>
</ul>
<h3 data-number="2.0.2" id="since-r4"><span class="header-section-number">2.0.2</span> Since R4<a href="#since-r4" class="self-link"></a></h3>
<ul>
<li>Clarifications and wording improvements.</li>
</ul>
<h3 data-number="2.0.3" id="since-r3"><span class="header-section-number">2.0.3</span> Since R3<a href="#since-r3" class="self-link"></a></h3>
<ul>
<li>Included changes to overload resolution.</li>
</ul>
<h3 data-number="2.0.4" id="since-r2"><span class="header-section-number">2.0.4</span> Since R2<a href="#since-r2" class="self-link"></a></h3>
<ul>
<li>Restricted effects of default argument deduction so it only applies
to partial ordering.</li>
</ul>
<h3 data-number="2.0.5" id="since-r1"><span class="header-section-number">2.0.5</span> Since R1<a href="#since-r1" class="self-link"></a></h3>
<ul>
<li>Improved solution’s notations and explanation.</li>
</ul>
<h3 data-number="2.0.6" id="since-r0"><span class="header-section-number">2.0.6</span> Since R0<a href="#since-r0" class="self-link"></a></h3>
<ul>
<li>Consequences of deducing default arguments for class templates are
further explored and the rules tweaked to make it work
consistently.</li>
<li>Consequences of deducing default arguments for packs are further
explored.</li>
<li>The problem of inconsistent deductions is further explored.</li>
<li>Added a paragraph on the consequences of mixing historical and P0522
affordances.</li>
</ul>
<h1 data-number="3" id="problem-1---default-arguments"><span class="header-section-number">3</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="3.1" id="solution-to-1"><span class="header-section-number">3.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="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> <span class="op">...</span> <span class="kw">class</span> Tn<span class="op">&gt;</span> TT1</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> U1<span class="op">,</span> <span class="op">...</span> <span class="kw">class</span> Un<span class="op">&gt;</span> TT2</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>P <span class="op">=</span> TT1<span class="op">&lt;</span>X1<span class="op">,</span> <span class="op">...,</span> Xn<span class="op">&gt;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>A <span class="op">=</span> TT2<span class="op">&lt;</span>Y1<span class="op">,</span> <span class="op">...,</span> Ym<span class="op">&gt;</span></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, only during partial ordering,
<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">Yn, <span class="op">...</span>, Ym</code>)
will be used as default arguments in this new invented TT1, replacing
any existing ones, effectively as if it had been written as:</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="op">...,</span> <span class="kw">class</span> Tn<span class="op">,</span> <span class="kw">class</span> Tn<span class="op">+</span><span class="dv">1</span> <span class="op">=</span> Yn<span class="op">+</span><span class="dv">1</span><span class="op">,</span> <span class="op">...,</span> <span class="kw">class</span> Tm <span class="op">=</span> Ym<span class="op">&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> TT1 <span class="op">=</span> TT2<span class="op">&lt;</span>T1<span class="op">,</span> <span class="op">...,</span> Tn<span class="op">,</span> Tn<span class="op">+</span><span class="dv">1</span><span class="op">,</span> <span class="op">...,</span> Tm<span class="op">&gt;</span></span></code></pre></div>
<p>That is, all template arguments used in the specialization of TT2,
which would not have been consumed had them been used in TT1, will be
used to deduce the default arguments for TT2.</p>
<p>In particular, this means that had
<code class="sourceCode cpp">Tn</code> been a parameter pack, no default
arguments will be deduced for <code class="sourceCode cpp">TT2</code>,
as that consumes all arguments.</p>
<p>When binding TT2 to TT1, the extra parameters are not accessible,
since the specialization to TT1 is checked at template parse time, so
the usage must match it’s declaration.</p>
<p>So it’s possible to conceptually simplify this, and think of this
alias template as:</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> T1<span class="op">,</span> <span class="op">...,</span> <span class="kw">class</span> Tn<span class="op">&gt;</span> <span class="kw">using</span> TT1 <span class="op">=</span> TT2<span class="op">&lt;</span>T1<span class="op">,</span> <span class="op">...,</span> Tn<span class="op">,</span> Yn<span class="op">+</span><span class="dv">1</span><span class="op">,</span> <span class="op">...,</span> Ym<span class="op">&gt;</span></span></code></pre></div>
<p>It’s useful to think of these invented templates in terms of the
equivalences proposed in <span class="citation" data-cites="CWG1286"><a href="https://wg21.link/cwg1286" role="doc-biblioref">[CWG1286]</a></span>, but the last proposed
resolution for that core issue only recognizes the first form.</p>
<p>This paper is not proposing to standardize a syntax to create this
implicit alias as written, outside of deduction, but for explanatory
purposes, the following syntax will be used: <code class="sourceCode cpp">A<span class="op">:</span><span class="dv">1</span><span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;</span></code>.</p>
<p>Where this means, take the template name
<code class="sourceCode cpp">A</code>, and create an alias from it by
applying the following template arguments as defaults, starting from the
second argument. Roughly equivalent to:</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">,</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="cb5-2"><a href="#cb5-2" 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">=</span> <span class="dt">float</span><span class="op">&gt;</span> <span class="kw">using</span> invented_alias_A_1_float <span class="op">=</span> A<span class="op">&lt;</span>T<span class="op">,</span> U<span class="op">&gt;;</span></span></code></pre></div>
<p>This syntax will be used in the rest of this chapter to convey this
adjustment.</p>
<h3 data-number="3.1.1" id="class-templates"><span class="header-section-number">3.1.1</span> Class templates<a href="#class-templates" class="self-link"></a></h3>
<p>Conversely, a template template parameter can also be deduced as a
class template:</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">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="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-3"><a href="#cb6-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="cb6-4"><a href="#cb6-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="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">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="op">{};</span> <span class="co">// #2</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a></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> 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 based on A, with
<code class="sourceCode cpp">T7</code> as default argument for
<code class="sourceCode cpp">T2</code>.</p>
<h3 data-number="3.1.2" id="consistency"><span class="header-section-number">3.1.2</span> Consistency<a href="#consistency" class="self-link"></a></h3>
<p>When a parameter is deduced against multiple arguments, there are
issues related to consistency, both in deduced and non-deduced
contexts.</p>
<p>Related to the former, given this 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">,</span> <span class="kw">class</span> T2<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> <span class="kw">class</span><span class="op">&gt;</span> <span class="kw">class</span> TT1<span class="op">,</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>
<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>T1<span class="op">,</span> T2<span class="op">&gt;,</span> TT1<span class="op">&lt;</span>T1<span class="op">,</span> T3<span class="op">&gt;&gt;</span> <span class="op">{};</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><span class="op">&gt;</span> <span class="kw">class</span> UU1<span class="op">,</span> <span class="kw">class</span> U1<span class="op">,</span> <span class="kw">class</span> U2<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>UU1<span class="op">&lt;</span>U1<span class="op">&gt;,</span> UU1<span class="op">&lt;</span>U2<span class="op">&gt;&gt;;</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="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;&gt;;</span></span></code></pre></div>
<p>Prior to P0522,
<code class="sourceCode cpp"><span class="pp">#1</span></code> would be
picked. This becomes ambiguous after
<code class="sourceCode cpp">P0522</code>, and the rules proposed in
this paper don’t help.</p>
<p>The problem is that <code class="sourceCode cpp">UU1</code> will be
deduced as both <code class="sourceCode cpp">TT1<span class="op">:</span><span class="dv">1</span><span class="op">&lt;</span>T2<span class="op">&gt;</span></code>
and <code class="sourceCode cpp">TT1<span class="op">:</span><span class="dv">1</span><span class="op">&lt;</span>T3<span class="op">&gt;</span></code>,
and these should in general be treated as different templates, so this
would be taken as an inconsistent deduction under current rules.</p>
<p>It should be possible to make this work and keep the pre P0522
behavior, but the present paper doesn’t go as far yet, and this is left
for future work.</p>
<p>This would involve recognizing that we are deducing two templates
against each other. <code class="sourceCode cpp">T2</code> and
<code class="sourceCode cpp">T3</code> are both template parameters of
it, and it’s consistent that they could be deduced to refer to the same
type.</p>
<p>Regarding consistency in non-deduced contexts, given this
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">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="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a></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">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="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">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="cb8-6"><a href="#cb8-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="cb8-7"><a href="#cb8-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="cb8-8"><a href="#cb8-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="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">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="cb8-11"><a href="#cb8-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="cb8-12"><a href="#cb8-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="cb8-13"><a href="#cb8-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="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-15"><a href="#cb8-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="cb8-16"><a href="#cb8-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">T2</code> for the default argument 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>This is a similar problem, and this paper does not propose a
mechanism to either keep both working, neither to reject both as
ambiguous. This is left for future work.</p>
<h3 data-number="3.1.3" id="packs"><span class="header-section-number">3.1.3</span> Packs<a href="#packs" class="self-link"></a></h3>
<p>As a particular consequence of this proposal, default arguments can
be deduced for pack parameters, something which is not ordinarily
possible to obtain.</p>
<p>This affects the partial ordering of the following example:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-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="cb9-2"><a href="#cb9-2" 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="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-4"><a href="#cb9-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>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><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="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" 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> T6<span class="op">,</span> <span class="kw">class</span> <span class="op">...</span>T7s<span class="op">&gt;</span> <span class="kw">class</span> TT2<span class="op">,</span> <span class="kw">class</span> T8<span class="op">,</span> <span class="kw">class</span> <span class="op">...</span>T9s<span class="op">&gt;</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> B<span class="op">&lt;</span>TT2<span class="op">&lt;</span>T8<span class="op">,</span> T9s<span class="op">...&gt;&gt;</span> <span class="op">{};</span> <span class="co">// #2</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-10"><a href="#cb9-10" 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>Before P0522,
<code class="sourceCode cpp"><span class="pp">#2</span></code> was
picked. After P0522, this changed entirely, now
<code class="sourceCode cpp"><span class="pp">#1</span></code> is
picked.</p>
<p>The proposed rules will restore the pre-P0522 behavior, picking
<code class="sourceCode cpp"><span class="pp">#2</span></code>
again.</p>
<h1 data-number="4" id="problem-2---with-vs-without-packs"><span class="header-section-number">4</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="cb10"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-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="cb10-2"><a href="#cb10-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="cb10-3"><a href="#cb10-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="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-5"><a href="#cb10-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="cb10-6"><a href="#cb10-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="cb10-7"><a href="#cb10-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="cb11"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-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="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-3"><a href="#cb11-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="cb11-4"><a href="#cb11-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="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-6"><a href="#cb11-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="cb11-7"><a href="#cb11-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="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-9"><a href="#cb11-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="cb11-10"><a href="#cb11-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>There is a historical rule which allows packs in the argument to
match non-packs in the parameter side.</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 historical rule.</p>
<p>Note that this is a check for whether the parameter is at least as
specialized as the argument, so the roles are switched around: P takes
the role of the argument, and A takes the role of the parameter.</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 only in the original direction which was accepted prior to
P0522, which was a pack on the argument side matching non-packs in the
parameter side.</p>
<p>Additionally, as a consequence of this exception, all implementations
seem to reject combinations of the P0522 and historical rule
affordances, which would otherwise be accepted individually, such as
this example:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-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="dt">int</span><span class="op">,</span> <span class="dt">int</span><span class="op">...&gt;</span> <span class="kw">class</span><span class="op">&gt;</span> <span class="kw">struct</span> A <span class="op">{};</span></span>
<span id="cb12-2"><a href="#cb12-2" 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="dt">char</span><span class="op">&gt;</span> <span class="kw">struct</span> B<span class="op">;</span></span>
<span id="cb12-3"><a href="#cb12-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></code></pre></div>
<p>Where there are packs in parameter side matching non-pack in argument
side, and also matching of NTTPs of different type.</p>
<p>This is a very arbitrary restriction, and we propose to make it clear
this is valid.</p>
<p>Now consider this example:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-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="cb13-2"><a href="#cb13-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="cb13-3"><a href="#cb13-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="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-5"><a href="#cb13-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="cb13-6"><a href="#cb13-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="cb13-7"><a href="#cb13-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="cb13-8"><a href="#cb13-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="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-10"><a href="#cb13-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="cb13-11"><a href="#cb13-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="cb13-12"><a href="#cb13-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="cb13-13"><a href="#cb13-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 remains: The <code class="sourceCode cpp">A<span class="op">&lt;</span>B<span class="op">&gt;</span></code>
specialization stays ambiguous. Here the problem goes outside of the
scope of partial ordering.</p>
<p>Now consider this example:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-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">&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 class="co">// #1</span></span>
<span id="cb14-2"><a href="#cb14-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> 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 class="co">// #2</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-4"><a href="#cb14-4" 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> A <span class="op">{};</span></span>
<span id="cb14-5"><a href="#cb14-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">...&gt;</span> <span class="kw">struct</span> B <span class="op">{};</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> test<span class="op">()</span> <span class="op">{</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>  f<span class="op">(</span>A<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;());</span> <span class="co">// selects #1</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>  f<span class="op">(</span>B<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;());</span> <span class="co">// selects #2</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>After P0522, both calls became ambiguous, but that’s so far only a
partial ordering issue, which the solution so far breaks in favor of
picking #1. But before P0522, overload resolution for the second call
would only match candidate #2. Picking #2 is the desirable outcome here,
since a pack seems to be a better match for a pack, and this would also
avoid a breaking change.</p>
<h2 data-number="4.1" id="solution-to-2"><span class="header-section-number">4.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 for a pack argument matching to
parameter non-packs, which is the opposite direction it’s normally
accepted in the deduction of template argument lists.</p>
<p>We also propose removing the classic pack exception clause in
<span>13.4.4
<a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>/3,
in favor of explicitly specifying that outside of partial ordering,
packs matching to non-packs must be accepted both ways.</p>
<p>Lastly, we propose to introduce a new kind of notional conversion for
the purpose of solving the overload resolution issue.</p>
<p>This is the same principle used in overload resolution, where
overloads are ranked according to the conversions involved when matching
arguments to their parameters. Some conversions are considered better
than others, which may lead to certain candidates being considered
better than others.</p>
<p>This new conversion would be defined by the presence of a pack on the
argument side matching a non-pack on the parameter side, whenever packs
matching non-packs would also be allowed in the opposite direction. A
candidate would be better when this conversion is not used.</p>
<h1 data-number="5" id="wording"><span class="header-section-number">5</span> Wording<a href="#wording" class="self-link"></a></h1>
<p>Add a new bullet after <span>12.2.4.1
<a href="https://wg21.link/over.match.best.general">[over.match.best.general]</a></span>/2.3:</p>
<blockquote>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span> the
context is an initialization by conversion function for direct reference
binding of a reference to function type, <em>[…]</em></li>
</ul>
<div class="add" style="color: #006e28">

<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.a)</a></span> Both
F1 and F2 are function template specializations, and there exists a
deduced or explicitly specified template template argument A for F2,
such that in a determination of whether A matches the corresponding
template parameter, the TTP-invented class
template ([temp.arg.template]) for A would use a strict pack
match ([temp.deduct.type]), and no such template template argument
exists for F1.</li>
</ul>
<div class="example">
<span>[ <em>Example:</em> </span>
<div class="sourceCode" id="cb1"><pre class="sourceCode default c++"><code class="sourceCode default"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class   &gt; class TT&gt; void f(TT&lt;int&gt;); // #1</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class...&gt; class TT&gt; void f(TT&lt;int&gt;); // #2</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>template &lt;class   &gt; struct A {};</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>template &lt;class...&gt; struct B {};</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>void test() {</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  f(A&lt;int&gt;()); // selects #1 because it is more specialized.</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  f(B&lt;int&gt;()); // selects #2, see above.</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>

</div>
</blockquote>
<p>Combine and modify <span>13.4.4
<a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>
paragraphs 4 and 5, moving the examples to subsequent paragraphs:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
A <em>template-argument</em> <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">A</code></span></ins></span>
matches a template <em>template-parameter</em>
<code class="sourceCode cpp">P</code> <span class="rm" style="color: #bf0303"><del>when
<span><code class="sourceCode default">P</code></span> is at least as
specialized as the <em>template-argument</em>
<span><code class="sourceCode default">A</code></span>.</del></span>
<span class="add" style="color: #006e28"><ins>when, given the following
rewrite to two function templates, the function template corresponding
to <span><code class="sourceCode default">P</code></span> is at least as
specialized as the function template corresponding to
<span><code class="sourceCode default">A</code></span> according to the
partial ordering rules for function templates (<span>13.7.7.3
<a href="https://wg21.link/temp.func.order">[temp.func.order]</a></span>),
ignoring constraints on A if P is unconstrained.</ins></span> <span class="rm" style="color: #bf0303"><del>In this comparison, if
<span><code class="sourceCode default">P</code></span> is unconstrained,
the constraints on
<span><code class="sourceCode default">A</code></span> are not
considered. If <span><code class="sourceCode default">P</code></span>
contains a template parameter pack, then
<span><code class="sourceCode default">A</code></span> also matches
<span><code class="sourceCode default">P</code></span> if each of
<span><code class="sourceCode default">A</code></span>’s template
parameters matches the corresponding template parameter in the
<em>template-head</em> of
<span><code class="sourceCode default">P</code></span>. Two template
parameters match if they are of the same kind (type, non-type,
template), for non-type <em>template-parameter</em>s, 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 <em>template-parameter</em>s, each of their
corresponding <em>template-parameter</em>s matches, recursively. When
<span><code class="sourceCode default">P</code></span>’s
<em>template-head</em> 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 <em>template-head</em> of
<span><code class="sourceCode default">A</code></span> with the same
type and form as the template parameter pack in
<span><code class="sourceCode default">P</code></span> (ignoring whether
those template parameters are template parameter
packs).</del></span></p>
<div class="example rm" style="color: #bf0303">
<p><span>[ <em>Example:</em> </span><em>[…]</em><span> — <em>end
example</em> ]</span></p>
</div>
<div class="example rm" style="color: #bf0303">
<p><span>[ <em>Example:</em> </span><em>[…]</em><span> — <em>end
example</em> ]</span></p>
</div>
<div class="example rm" style="color: #bf0303">
<p><span>[ <em>Example:</em> </span><em>[…]</em><span> — <em>end
example</em> ]</span></p>
</div>
<p><span class="rm" style="color: #bf0303"><del>A template
<em>template-parameter</em>
<span><code class="sourceCode default">P</code></span> is at least as
specialized as a template <em>template-argument</em>
<span><code class="sourceCode default">A</code></span> if, given the
following rewrite to two function templates, the function template
corresponding to <span><code class="sourceCode default">P</code></span>
is at least as specialized as the function template corresponding to
<span><code class="sourceCode default">A</code></span> according to the
partial ordering rules for function templates (<span>13.7.7.3
<a href="https://wg21.link/temp.func.order">[temp.func.order]</a></span>).</del></span>
Given an invented class template <code class="sourceCode cpp">X</code>
with the <em>template-head</em> of <code class="sourceCode cpp">A</code>
(including default arguments and <em>requires-clause</em>, if any)<span class="add" style="color: #006e28"><ins>, termed a <em>TTP-invented
class template</em></ins></span>:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> Each
of the two function templates has the same template parameters and
<em>requires-clause</em> (if any), respectively, as
<code class="sourceCode cpp">P</code> or
<code class="sourceCode cpp">A</code>.</li>
<li><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> Each
function template has a single function parameter whose type is a
specialization of <code class="sourceCode cpp">X</code> with template
arguments corresponding to the template parameters from the respective
function template where, for each template parameter
<code class="sourceCode cpp">PP</code> in the <em>template-head</em> of
the function template, a corresponding template argument
<code class="sourceCode cpp">AA</code> is formed. If
<code class="sourceCode cpp">PP</code> declares a template parameter
pack, then <code class="sourceCode cpp">AA</code> is the pack expansion
<code class="sourceCode cpp">PP<span class="op">...</span></code> (<span>13.7.4
<a href="https://wg21.link/temp.variadic">[temp.variadic]</a></span>);
otherwise, <code class="sourceCode cpp">AA</code> is the
<em>id-expression</em> <code class="sourceCode cpp">PP</code>.</li>
</ul>
<p>If the rewrite produces an invalid type, then
<code class="sourceCode cpp">P</code> is not at least as specialized as
<code class="sourceCode cpp">A</code>.</p>
<div class="add" style="color: #006e28">
<p><span class="note"><span>[ <em>Note:</em> </span>[temp.deduct.type]
has a special case for this deduction.<span> — <em>end note</em>
]</span></span></p>
</div>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<span class="example"><span>[ <em>Example:</em>
</span><em>[…]</em><span> — <em>end example</em> ]</span></span></p>
</div>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<span class="example"><span>[ <em>Example:</em>
</span><em>[…]</em><span> — <em>end example</em> ]</span></span></p>
</div>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<span class="example"><span>[ <em>Example:</em>
</span><em>[…]</em><span> — <em>end example</em> ]</span></span></p>
</div>
</blockquote>
<p>Add the following new examples immediately after the above:</p>
<blockquote>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">a</a></span></p>
<div class="example">
<span>[ <em>Example:</em> </span>
<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 T1&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, class T&gt; struct A&lt;TT&lt;T&gt;&gt;; // #1</span>
<span id="cb2-3"><a href="#cb2-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="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>template&lt;class&gt; struct B;</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>template struct A&lt;B&lt;int&gt;&gt;; // selects #2</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class...&gt; class TT&gt; struct C; // #3</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class&gt; class TT&gt; struct C&lt;TT&gt;; // OK, more specialized than #3</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class&gt; class TT&gt; struct D; // #4</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class...&gt; class TT&gt; struct D&lt;TT&gt;; // error: not more specialized than #4</span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>

</div>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">b</a></span></p>
<div class="example">
<span>[ <em>Example:</em> </span>
<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;template&lt;class, char, char...&gt; class&gt; struct A {};</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>template&lt;class, int&gt; struct B;</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>template struct A&lt;B&gt;; // OK, `char` matches &#39;int&#39;, pack matching non-pack is accepted.</span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>

</div>
</blockquote>
<p>Add a new paragraph after <span>13.10.3.6
<a href="https://wg21.link/temp.deduct.type">[temp.deduct.type]</a></span>/8:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>[…]</em> Similarly, <code class="sourceCode cpp"><span class="op">&lt;</span>X<span class="op">&gt;</span></code>
represents template argument lists where at least one argument contains
a <code class="sourceCode cpp">X</code>, where
<code class="sourceCode cpp">X</code> is one of
<code class="sourceCode cpp">T</code>,
<code class="sourceCode cpp">i</code>,
<code class="sourceCode cpp">TT</code>, or
<code class="sourceCode cpp">VV</code>; and
<code class="sourceCode cpp"><span class="op">&lt;&gt;</span></code>
represents template argument lists where no argument contains a
<code class="sourceCode cpp">T</code>, an
<code class="sourceCode cpp">i</code>, a
<code class="sourceCode cpp">TT</code>, or a
<code class="sourceCode cpp">VV</code>.</p>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">a</a></span>
If P is a specialization of a template template parameter, the argument
corresponding to the parameter is deduced as a new invented template,
which is identical to the original template except for its
<em>template-head</em>. Each element of the invented template’s
<em>template-head</em> following the initial sequence of parameters that
have a matching argument in P has as its default argument the matching
template argument (or a pack of the matching arguments, if the element
declares a pack) in <code class="sourceCode default">A</code>. These
invented templates, along with their original templates, form an
equivalence class, where they are equivalent if and only if they
originate from the same template and have equivalent default
arguments.</p>
<div class="example">
<span>[ <em>Example:</em> </span>
<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, class = float&gt; struct A {};</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;template &lt;class&gt; class TT, class T&gt; void f(TT&lt;T&gt;);                    // #1</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class, class&gt; class TT, class T, class U&gt; void f(TT&lt;T, U&gt;); // #2</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class&gt; class TT, class T&gt; void g(TT&lt;T&gt;); // #3</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>template &lt;class T, class U&gt; void g(A&lt;T, U&gt;);                 // #4</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>void test(A&lt;int&gt; a) {</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>  f(a); // selects #2</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>  g(a); // selects #4</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>
<div class="example">
<span>[ <em>Example:</em> </span>
<div class="sourceCode" id="cb5"><pre class="sourceCode default c++"><code class="sourceCode default"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class T&gt; class TT&gt; void f(TT1&lt;int&gt;, TT1&lt;char&gt;); // #1</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class T, class U&gt; class TT2&gt; void f(TT2&lt;int, void&gt;, TT2&lt;char, void&gt;) // #2</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>template &lt;class, class = void&gt; struct A {};</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>template void f&lt;A&gt;(A&lt;int&gt;, A&lt;char&gt;); // selects #2</span></code></pre></div>
<p>When checking if <code class="sourceCode default">#1</code> is at
least as specialized as <code class="sourceCode default">#2</code>, TT1
is deduced two times:</p>
<ol type="1">
<li><code class="sourceCode default">P = TT1&lt;int&gt;; A = TT2&lt;int, void&gt;</code></li>
<li><code class="sourceCode default">P = TT1&lt;char&gt;; A = TT2&lt;char, void&gt;</code></li>
</ol>
<p>In both, TT1 is deduced as TT2 modified with void as default argument
for the second parameter, making this a consistent deduction.<span> —
<em>end example</em> ]</span></p>
</div>

</div>
</blockquote>
<p>Modify <span>13.10.3.6
<a href="https://wg21.link/temp.deduct.type">[temp.deduct.type]</a></span>/9,
breaking its ending into new bullets:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
If P has a form that contains &lt;T&gt;, &lt;i&gt;, &lt;TT&gt;, or
&lt;VV&gt;, 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.</p>
</blockquote>
<p>Break into a new bullet here:</p>
<blockquote>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(9.1)</a></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>.</li>
</ul>
</blockquote>
<p>Break into a new bullet here, also prepending a new bullet:</p>
<blockquote>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span>
<span class="add" style="color: #006e28"><ins>If P is a TTP-invented
class template ([temp.arg.template]), P uses a <em>strict pack
match</em> when a non-pack argument in its argument list matches a pack
expansion in A.</ins></span></li>
</ul>
</blockquote>
<p>Continue modification with new bullet formed from original
paragraph:</p>
<blockquote>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.3)</a></span>
During partial ordering, if A<sub>i</sub> was originally a pack
expansion:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.3.1)</a></span>
<span class="add" style="color: #006e28"><ins>if P uses a strict pack
match, template argument deduction fails;</ins></span></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.3.2)</a></span>
<span class="add" style="color: #006e28"><ins>otherwise,</ins></span> if
P does not contain a template argument corresponding to A<sub>i</sub>
then A<sub>i</sub> is ignored;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.3.3)</a></span>
otherwise, if P<sub>i</sub> is not a pack expansion, template argument
deduction fails.</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.4)</a></span>
<span class="add" style="color: #006e28"><ins>When deducing the argument
list of the specializations of a TTP-invented class
template ([temp.arg.template]), if A<sub>i</sub> is a pack expansion,
and there is at least one remaining argument in P, 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
P<sub>i</sub>. If P<sub>i</sub> is a pack expansion, template argument
deduction fails.</ins></span></p></li>
</ul>
<div class="note add" style="color: #006e28">
<p><span>[ <em>Note:</em> </span>The last two bullets are the reverse of
each other.<span> — <em>end note</em> ]</span></p>
</div>
</blockquote>
<p>Add a new bullet to <span>13.7.6.2
<a href="https://wg21.link/temp.spec.partial.match">[temp.spec.partial.match]</a></span>/1
and append a new example to the next paragraph:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
When a template is used in a context that requires an instantiation of
the template, it is necessary to determine whether the instantiation is
to be generated using the primary template or one of the partial
specializations. This is done by matching the template arguments of the
template specialization with the template argument lists of the partial
specializations.</p>
<ul>
<li><p>Each of the two function templates has the same template
parameters and associated constraints as the corresponding partial
specialization.</p></li>
<li><p>Each function template has a single function parameter whose type
is a class template specialization where the template arguments are the
corresponding template parameters from the function template for each
template argument in the template-argument-list of the
simple-template-id of the partial specialization.</p></li>
</ul>
<div class="add" style="color: #006e28">

<ul>
<li>If a matching specialization (including the primary template) uses a
strict pack match ([temp.deduct.type]), that specialization is
considered only if there are no matching specializations that do not use
a strict pack match.</li>
</ul>

</div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span><span class="example"><span>[ <em>Example:</em> </span><em>[…]</em><span> —
<em>end example</em> ]</span></span></p>
<p><span class="example"><span>[ <em>Example:</em>
</span><em>[…]</em><span> — <em>end example</em> ]</span></span></p>
<div class="add" style="color: #006e28">

<div class="example">
<span>[ <em>Example:</em> </span>
<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;template&lt;class...&gt; class&gt; struct A;     // #1</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>template&lt;template&lt;class&gt; class TT&gt; struct A&lt;TT&gt;; // #2</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>template&lt;class...&gt; struct B;</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>template&lt;class&gt; struct C;</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>template struct A&lt;B&gt;; // selects #1</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>template struct A&lt;C&gt;; // selects #2</span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>
<p>When instantiating A&lt;B&gt;, matching B to #2 uses a strict pack
match ([temp.deduct.type]), while #1 does not, so #1 is a better
match.</p>
</div>
</blockquote>
<p>Update feature test macro in <span>15.11
<a href="https://wg21.link/cpp.predefined">[cpp.predefined]</a></span>
table 22</p>
<blockquote>
<p>__cpp_template_template_args <span class="rm" style="color: #bf0303"><del>201611L</del></span><span class="add" style="color: #006e28"><ins>2025XXL</ins></span></p>
</blockquote>
<h1 data-number="6" id="acknowledgements"><span class="header-section-number">6</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>Many thanks to those who have reviewed, contributed suggestions, and
otherwise helped the paper reach it’s current state: Arthur O’Dwyer,
Brian Bi, Corentin Jabot, James Touton, Jens Maurer, Richard Smith.</p>
<h1 data-number="7" id="bibliography"><span class="header-section-number">7</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-CWG1286" class="csl-entry" role="doc-biblioentry">
[CWG1286] Gabriel Dos Reis. 2011-04-03. Equivalence of alias templates.
<a href="https://wg21.link/cwg1286"><div class="csl-block">https://wg21.link/cwg1286</div></a>
</div>
<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>
