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

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

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

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

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">Solving issues introduced by
P0522R0</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3310R4</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-10-15</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>
    </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="#problem-1" id="toc-problem-1"><span class="toc-section-number">2.1</span> Problem #1<span></span></a>
<ul>
<li><a href="#since-r2" id="toc-since-r2"><span class="toc-section-number">2.1.1</span> Since R2<span></span></a></li>
<li><a href="#since-r1" id="toc-since-r1"><span class="toc-section-number">2.1.2</span> Since R1<span></span></a></li>
<li><a href="#since-r0" id="toc-since-r0"><span class="toc-section-number">2.1.3</span> Since R0<span></span></a></li>
</ul></li>
<li><a href="#problem-2" id="toc-problem-2"><span class="toc-section-number">2.2</span> Problem #2<span></span></a>
<ul>
<li><a href="#since-r3" id="toc-since-r3"><span class="toc-section-number">2.2.1</span> Since R3<span></span></a></li>
<li><a href="#since-r0-1" id="toc-since-r0-1"><span class="toc-section-number">2.2.2</span> Since R0<span></span></a></li>
</ul></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 P0522R0 into C++17, later made a defect report, which
relaxed the rules on how templates are matched to template template
parameters, but didn’t concern itself with how partial ordering 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>
<h2 data-number="2.1" id="problem-1"><span class="header-section-number">2.1</span> Problem #1<a href="#problem-1" class="self-link"></a></h2>
<h3 data-number="2.1.1" id="since-r2"><span class="header-section-number">2.1.1</span> Since R2<a href="#since-r2" class="self-link"></a></h3>
<ul>
<li>Restricted effects of the change so it only applies to partial
ordering.</li>
</ul>
<h3 data-number="2.1.2" id="since-r1"><span class="header-section-number">2.1.2</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.1.3" id="since-r0"><span class="header-section-number">2.1.3</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>
</ul>
<h2 data-number="2.2" id="problem-2"><span class="header-section-number">2.2</span> Problem #2<a href="#problem-2" class="self-link"></a></h2>
<h3 data-number="2.2.1" id="since-r3"><span class="header-section-number">2.2.1</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.2.2" id="since-r0-1"><span class="header-section-number">2.2.2</span> Since R0<a href="#since-r0-1" class="self-link"></a></h3>
<ul>
<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>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-3"><a href="#cb2-3" 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,
<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 TT2, 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 class="kw">class</span> TT2</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 parameter to
match non-packs in the argument 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>We propose a solution which will restore the semantics of the second
example, by specifying that during partial ordering, packs must match
non-packs in only one direction.</p>
<p>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 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">// picks #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">// picks #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 in the argument to parameter direction,
which is the opposite direction it’s normally accepted in the deduction
of template argument lists.</p>
<p>We also propose scratching the classic pack exception clause in
<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, parameter to
argument as well as argument to parameter.</p>
<p>Lastly, we propose to introduce a new kind of conversion for the
purpose of solving the partial ordering issue. This 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>
<p>When matching candidates against the primary template and partial
specialziations, we first perform overload resolution with the set of
candidates which did not perform this conversion. If there is no viable
candidate, including a not viable primary template, do overload
resolution again using the complement of the first set of
candidates.</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 paragraph after <span>13.7.7.3
<a href="https://wg21.link/temp.func.order">[temp.func.order]</a></span>/2:</p>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
Except while partial ordering, when deducing the argument list of X as
specified in 13.4.4 [temp.arg.template]/4, partial ordering considers
first the set of templates which do not apply <span>13.10.3.6
<a href="https://wg21.link/temp.deduct.type">[temp.deduct.type]</a></span>/9.2,
possibly including the primary template. If there is no viable template
in this first set, partial ordering considers the rest.</p>
</div>
<p>Add a new paragraph after <span>13.7.7.3
<a href="https://wg21.link/temp.func.order">[temp.func.order]</a></span>/5:</p>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
- When matching template template parameters as described in
<span>13.10.3.6
<a href="https://wg21.link/temp.deduct.type">[temp.deduct.type]</a></span>/8,
if P is a specialization of a template template parameter, and A is
either also the same kind, or a class template specialization, the
template template parameter in P will be deduced as a modified template
A, as if the template argument list in A were used as the default
arguments for its template parameters, starting from the first parameter
which has a correspondence in P, up to the last parameter which has a
corresponding argument.</p>
<p>[Example:</p>
<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;class, class = float&gt; struct A;</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>template &lt;class&gt; struct B;</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class&gt; class TT, class T&gt; struct B&lt;TT&lt;T&gt;&gt;;   // #1</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>template &lt;class T, class U&gt;                   struct B&lt;A&lt;T, U&gt;&gt;; // #2</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>template struct B&lt;A&lt;int&gt;&gt;; // selects #2</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>template &lt;class&gt; struct C;</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class&gt; class TT, class T&gt; struct C&lt;TT&lt;T&gt;&gt;;   // #3</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>template &lt;class T, class U&gt;                   struct C&lt;A&lt;T, U&gt;&gt;; // #4</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>template struct C&lt;A&lt;int&gt;&gt;; // selects #4</span></code></pre></div>
<ul>
<li>end example]</li>
</ul>

</div>
<p>Modify <span>13.10.3.6
<a href="https://wg21.link/temp.deduct.type">[temp.deduct.type]</a></span>/9:</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
If P has a form that contains &lt;T&gt;<span class="rm" style="color: #bf0303"><del>or</del></span><span class="add" style="color: #006e28"><ins>,</ins></span> &lt;i&gt;, <span class="add" style="color: #006e28"><ins>or &lt;TT<sub>opt</sub>&gt;,</ins></span>
then each argument P<sub>i</sub> of the respective template argument
list of P is compared with the corresponding argument A<sub>i</sub> of
the corresponding template argument list of A. If the template argument
list of P contains a pack expansion that is not the last template
argument, the entire template argument list is a non-deduced context.
<span class="rm" style="color: #bf0303"><del>If P<sub>i</sub> is a pack
expansion, then the pattern of P<sub>i</sub> is compared with each
remaining argument in the template argument list of A. Each comparison
deduces template arguments for subsequent positions in the template
parameter packs expanded by P<sub>i</sub>. During partial ordering, if
A<sub>i</sub> was originally a pack expansion:</del></span></p>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span>
<span class="add" style="color: #006e28"><ins>While partial ordering,
except when deducing the argument list of X as specified in <span>13.4.4
<a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>/4,</ins></span>
if P<sub>i</sub> is a pack expansion, then the pattern of P<sub>i</sub>
is compared with each remaining argument in the template argument list
of A. Each comparison deduces template arguments for subsequent
positions in the template parameter packs expanded by P<sub>i</sub>.
During partial ordering, if A<sub>i</sub> was originally a pack
expansion:</p>
<p><span class="marginalizedparent"><a class="marginalized">(9.1.1)</a></span> -
if P does not contain a template argument corresponding to A<sub>i</sub>
then A<sub>i</sub> is ignored;</p>
<p><span class="marginalizedparent"><a class="marginalized">(9.1.2)</a></span> -
otherwise, if P<sub>i</sub> is not a pack expansion, template argument
deduction fails.</p>
<p><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span>
<span class="add" style="color: #006e28"><ins>When deducing the argument
list of X as specified in <span>13.4.4
<a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>/4,
if A<sub>i</sub> is a pack expansion, 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 A<sub>i</sub>. If P<sub>i</sub> was
originally a pack expansion:</ins></span></p>
<p><span class="marginalizedparent"><a class="marginalized">(9.2.1)</a></span> -
<span class="add" style="color: #006e28"><ins>if A does not contain a
template argument corresponding to P<sub>i</sub> then P<sub>i</sub> is
ignored;</ins></span></p>
<p><span class="marginalizedparent"><a class="marginalized">(9.2.2)</a></span> -
<span class="add" style="color: #006e28"><ins>otherwise, template
argument deduction fails.</ins></span></p>
<p>[Note: (9.2) is the reverse of (9.1) - end note]</p>
</div>
<p>Modify <span>13.4.4
<a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>/3:</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
A template-argument matches a template template-parameter P when P is at
least as specialized as the template-argument A. In this comparison, if
P is unconstrained, the constraints on A are not considered. <span class="rm" style="color: #bf0303"><del>If P contains a template
parameter pack, then A also matches P if each of A’s template parameters
matches the corresponding template parameter in the template-head of
P</del></span>. Two template parameters match if they are of the same
kind (type, non-type, template), for non-type template-parameters, their
types are equivalent (<span>13.7.7.2
<a href="https://wg21.link/temp.over.link">[temp.over.link]</a></span>),
and for template template-parameters, each of their corresponding
template-parameters matches, recursively. When P’s template-head
contains a template parameter pack (<span>13.7.4
<a href="https://wg21.link/temp.variadic">[temp.variadic]</a></span>),
the template parameter pack will match zero or more template parameters
or template parameter packs in the template-head of A with the same type
and form as the template parameter pack in P (ignoring whether those
template parameters are template parameter packs).</p>
<p>Append note and example to <span>13.4.4
<a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>/4:</p>
<div class="add" style="color: #006e28">
<p>[Note: <span>13.10.3.6
<a href="https://wg21.link/temp.deduct.type">[temp.deduct.type]</a></span>/9
has a special case for this deduction - end note]</p>
<p>[Example:</p>
<div class="sourceCode" id="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;</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>// This partial specialization is more specialized than the primary template.</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class&gt; class TT&gt; struct C&lt;TT&gt;;</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a></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;</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>// This partial specialization is NOT more specialized than the primary template.</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class...&gt; class TT&gt; struct D&lt;TT&gt;;</span></code></pre></div>
<ul>
<li>end example]</li>
</ul>
<p>[Example:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode default c++"><code class="sourceCode default"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>template&lt;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>// OK, `char` matches &#39;int&#39;, pack matching non-pack is accepted.</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>template struct A&lt;B&gt;;</span></code></pre></div>
<ul>
<li>end example]</li>
</ul>

</div>
<p>Add a new paragraph after <span>12.2.4.1
<a href="https://wg21.link/over.match.best.general">[over.match.best.general]</a></span>/2.3:</p>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">(2.4)</a></span>
Except while partial ordering, when deducing the argument list of X as
specified in 13.4.4 [temp.arg.template]/4, F1 does not apply
<span>13.10.3.6
<a href="https://wg21.link/temp.deduct.type">[temp.deduct.type]</a></span>/9.2,
and F2 does.</p>
<p>[Example:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode default c++"><code class="sourceCode default"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>template &lt;template &lt;class   &gt; class TT&gt; void f(TT&lt;int&gt;); // #1</span>
<span id="cb4-2"><a href="#cb4-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="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>template &lt;class   &gt; struct A {};</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>template &lt;class...&gt; struct B {};</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>void test() {</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  f(A&lt;int&gt;()); // picks #1</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  f(B&lt;int&gt;()); // picks #2</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>

</div>
<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,
Corentin Jabot, James Touton, 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>
