<!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-07-11" />
  <title>Fixing `std::complex` binary operators</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">Fixing
<code class="sourceCode cpp">std<span class="op">::</span>complex</code>
binary operators</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>
      P3788R0
      [<a href="https://wg21.link/P3788">Latest</a>]
      [<a href="https://wg21.link/P3788/status">Status</a>]
    </td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-07-11</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>
      SG6 Numerics<br>
      Library Evolution Working Group<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Mateusz Pusz (<a href="http://www.epam.com">Epam
Systems</a>)<br>&lt;<a href="mailto:mateusz.pusz@gmail.com" class="email">mateusz.pusz@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="#motivation" id="toc-motivation"><span class="toc-section-number">2</span> Motivation<span></span></a></li>
<li><a href="#problem-statement" id="toc-problem-statement"><span class="toc-section-number">3</span> Problem
statement<span></span></a></li>
<li><a href="#hidden-friends-are-not-a-solution-here" id="toc-hidden-friends-are-not-a-solution-here"><span class="toc-section-number">4</span> Hidden friends are not a solution
here<span></span></a></li>
<li><a href="#fixing-conversions-to-t-scalar-function-template-parameters" id="toc-fixing-conversions-to-t-scalar-function-template-parameters"><span class="toc-section-number">5</span> Fixing conversions to
<code class="sourceCode cpp">T</code> scalar function template
parameters<span></span></a></li>
<li><a href="#fixing-overloads-with-heterogeneous-types" id="toc-fixing-overloads-with-heterogeneous-types"><span class="toc-section-number">6</span> Fixing overloads with heterogeneous
types<span></span></a></li>
<li><a href="#impact-on-existing-code" id="toc-impact-on-existing-code"><span class="toc-section-number">7</span> Impact on existing
code<span></span></a></li>
<li><a href="#implementation-considerations" id="toc-implementation-considerations"><span class="toc-section-number">8</span> Implementation
considerations<span></span></a></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">9</span> Wording<span></span></a>
<ul>
<li><a href="#complex.syn" id="toc-complex.syn"><span class="toc-section-number">9.1</span>
<span>[complex.syn]</span><span></span></a></li>
<li><a href="#complex.ops" id="toc-complex.ops"><span class="toc-section-number">9.2</span>
<span>[complex.ops]</span><span></span></a></li>
<li><a href="#feature-test-macro" id="toc-feature-test-macro"><span class="toc-section-number">9.3</span> Feature test
macro<span></span></a></li>
<li><a href="#optional-heterogeneous-type-support" id="toc-optional-heterogeneous-type-support"><span class="toc-section-number">9.4</span> Optional: Heterogeneous type
support<span></span></a></li>
</ul></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">10</span>
Acknowledgements<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">11</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 proposes a backward-compatible solution to fix the
inconsistent behavior of
<code class="sourceCode cpp">std<span class="op">::</span>complex</code>
binary operators with implicit conversions. The proposed changes:</p>
<ol type="1">
<li>Enable implicit conversions for scalar operands in
<code class="sourceCode cpp">std<span class="op">::</span>complex</code>
binary operations.</li>
<li>Optionally support mixed-type complex operations.</li>
<li>Maintain full backward compatibility with existing code.</li>
</ol>
<h1 data-number="2" id="motivation"><span class="header-section-number">2</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<p>Consider the following natural mathematical operations with complex
numbers:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt">long</span> <span class="dt">double</span> ld <span class="op">=</span> <span class="fl">2.5</span>;</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>complex<span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;</span> c <span class="op">=</span> <span class="fl">3.14</span>;           <span class="co">// OK!!!</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> res1 <span class="op">=</span> c <span class="op">*</span> <span class="fl">3.14</span><span class="bu">f</span>;                  <span class="co">// OK</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> res2 <span class="op">=</span> c <span class="op">*</span> <span class="fl">3.14</span>;                   <span class="co">// DOES NOT COMPILE!!!</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> res3 <span class="op">=</span> c <span class="op">*</span> ld;                     <span class="co">// DOES NOT COMPILE!!!</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> res4 <span class="op">=</span> c <span class="op">*</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;(</span>ld<span class="op">)</span>; <span class="co">// OK but verbose</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(</span>c <span class="op">==</span> <span class="fl">3.14</span><span class="bu">f</span><span class="op">)</span> <span class="op">{</span>                       <span class="co">// OK</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">// ...</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(</span>c <span class="op">==</span> <span class="fl">3.14</span><span class="op">)</span> <span class="op">{</span>                        <span class="co">// DOES NOT COMPILE!!!</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>  <span class="co">// ...</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The above behavior is surprising and violates good design practices.
It is a well-established design rule that if a type
<code class="sourceCode cpp">T</code> is convertible to type
<code class="sourceCode cpp">U</code>, then a binary operator on types
<code class="sourceCode cpp">T</code> and
<code class="sourceCode cpp">U</code> should also work correctly. This
issue affects user experience and forces developers to explicitly cast
literals and variables of compatible types, making mathematical code
less readable and more error-prone.</p>
<p>Additionally,
<code class="sourceCode cpp">std<span class="op">::</span>complex</code>
is problematic in generic contexts. Here is an excerpt from the mp-units
library:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><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">typename</span> T<span class="op">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> scaling_factor_type_t <span class="op">=</span> conditional<span class="op">&lt;</span>treat_as_floating_point<span class="op">&lt;</span>T<span class="op">&gt;</span>, <span class="dt">long</span> <span class="dt">double</span>, std<span class="op">::</span><span class="dt">intmax_t</span><span class="op">&gt;</span>;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> ScalableByFactor <span class="op">=</span> <span class="kw">requires</span><span class="op">(</span><span class="kw">const</span> T v, <span class="kw">const</span> scaling_factor_type_t<span class="op">&lt;</span>T<span class="op">&gt;</span> f<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span> v<span class="op">*</span> f <span class="op">}</span> <span class="op">-&gt;</span> std<span class="op">::</span>common_with<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span> f<span class="op">*</span> v <span class="op">}</span> <span class="op">-&gt;</span> std<span class="op">::</span>common_with<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span> v <span class="op">/</span> f <span class="op">}</span> <span class="op">-&gt;</span> std<span class="op">::</span>common_with<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</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><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> RealScalarRepresentation <span class="op">=</span> <span class="op">(!</span>Quantity<span class="op">&lt;</span>T<span class="op">&gt;)</span> <span class="op">&amp;&amp;</span> RealScalar<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> ScalableByFactor<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> ComplexScalarRepresentation <span class="op">=</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>  <span class="op">(!</span>Quantity<span class="op">&lt;</span>T<span class="op">&gt;)</span> <span class="op">&amp;&amp;</span> ComplexScalar<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> <span class="kw">requires</span><span class="op">(</span><span class="kw">const</span> T v, <span class="kw">const</span> scaling_factor_type_t<span class="op">&lt;</span>T<span class="op">&gt;</span> f<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>    <span class="co">// </span><span class="al">TODO</span><span class="co"> The below conversion to `T` is an exception compared to other representation types</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>    <span class="co">// `std::complex&lt;T&gt;` * `U` do not work, but `std::complex&lt;T&gt;` is convertible from `U`</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span> v<span class="op">*</span> T<span class="op">(</span>f<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> std<span class="op">::</span>common_with<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span> T<span class="op">(</span>f<span class="op">)</span> <span class="op">*</span> v <span class="op">}</span> <span class="op">-&gt;</span> std<span class="op">::</span>common_with<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span> v <span class="op">/</span> T<span class="op">(</span>f<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> std<span class="op">::</span>common_with<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> ScalarRepresentation <span class="op">=</span> RealScalarRepresentation<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">||</span> ComplexScalarRepresentation<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> VectorRepresentation <span class="op">=</span> NotQuantity<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> Vector<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> ScalableByFactor<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span></code></pre></div>
<p>As seen above, the general-purpose physical quantities and units
library has to special-case the
<code class="sourceCode cpp">std<span class="op">::</span>complex</code>
type to handle scaling of a quantity value between different units. This
is wrong and should not be required for C++ Standard Library types.</p>
<h1 data-number="3" id="problem-statement"><span class="header-section-number">3</span> Problem statement<a href="#problem-statement" class="self-link"></a></h1>
<p><code class="sourceCode cpp">std<span class="op">::</span>complex</code>
is implicitly constructible from its representation type
<code class="sourceCode cpp">T</code>. The non-explicit constructor
takes type <code class="sourceCode cpp">T</code> as a regular function
parameter type (not a dependent name). This means that all standard and
user-defined conversions apply to this function parameter in such a
constructor call.</p>
<p>However, all binary operators are defined as non-member non-friend
overloads where <code class="sourceCode cpp">T</code> is a deduced
template parameter type. For example:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><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> T<span class="op">&gt;</span> <span class="kw">constexpr</span> complex<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">*(</span><span class="kw">const</span> complex<span class="op">&lt;</span>T<span class="op">&gt;&amp;</span>, <span class="kw">const</span> complex<span class="op">&lt;</span>T<span class="op">&gt;&amp;)</span>;</span>
<span id="cb3-2"><a href="#cb3-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">&gt;</span> <span class="kw">constexpr</span> complex<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">*(</span><span class="kw">const</span> complex<span class="op">&lt;</span>T<span class="op">&gt;&amp;</span>, <span class="kw">const</span> T<span class="op">&amp;)</span>;</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span> <span class="kw">constexpr</span> complex<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">*(</span><span class="kw">const</span> T<span class="op">&amp;</span>, <span class="kw">const</span> complex<span class="op">&lt;</span>T<span class="op">&gt;&amp;)</span>;</span></code></pre></div>
<p>According to template argument deduction rules, most conversions are
not allowed for standalone function template parameters of type
<code class="sourceCode cpp">T</code>. This means that there is no
overload that can accept <code class="sourceCode cpp">std<span class="op">::</span>complex<span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;</span></code>
and a <code class="sourceCode cpp"><span class="dt">double</span></code>
as its arguments.</p>
<p>Additionally, we cannot perform operations on complex numbers of
different types (e.g., <code class="sourceCode cpp">complex<span class="op">&lt;</span><span class="dt">double</span><span class="op">&gt;</span></code>
and <code class="sourceCode cpp">complex<span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;</span></code>).</p>
<h1 data-number="4" id="hidden-friends-are-not-a-solution-here"><span class="header-section-number">4</span> Hidden friends are not a solution
here<a href="#hidden-friends-are-not-a-solution-here" class="self-link"></a></h1>
<p>Making those operators hidden friends would immediately solve all the
issues described above. However, this would be an API break for any code
that relies on them being declared at namespace scope, e.g., code that
calls <code class="sourceCode cpp">std<span class="op">::</span><span class="kw">operator</span><span class="op">*&lt;</span><span class="dt">float</span><span class="op">&gt;(</span>c, <span class="fl">3.14</span><span class="op">)</span></code>,
or similar constructs.</p>
<h1 data-number="5" id="fixing-conversions-to-t-scalar-function-template-parameters"><span class="header-section-number">5</span> Fixing conversions to
<code class="sourceCode cpp">T</code> scalar function template
parameters<a href="#fixing-conversions-to-t-scalar-function-template-parameters" class="self-link"></a></h1>
<p>We propose to fix the conversions to
<code class="sourceCode cpp">T</code> in a similar way that <span class="citation" data-cites="P0558R1"><a href="https://wg21.link/p0558r1" role="doc-biblioref">[P0558R1]</a></span> fixed
<code class="sourceCode cpp">std<span class="op">::</span>atomic</code>
interfaces. Instead of using type <code class="sourceCode cpp">T</code>
as a function template parameter, we can use <code class="sourceCode cpp"><span class="kw">typename</span> std<span class="op">::</span>complex<span class="op">&lt;</span>T<span class="op">&gt;::</span>value_type</code>
instead:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span> <span class="kw">constexpr</span> complex<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">*(</span><span class="kw">const</span> complex<span class="op">&lt;</span>T<span class="op">&gt;&amp;</span>, <span class="kw">const</span> complex<span class="op">&lt;</span>T<span class="op">&gt;&amp;)</span>;</span>
<span id="cb4-2"><a href="#cb4-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">&gt;</span> <span class="kw">constexpr</span> complex<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">*(</span><span class="kw">const</span> complex<span class="op">&lt;</span>T<span class="op">&gt;&amp;</span>, <span class="kw">const</span> <span class="kw">typename</span> complex<span class="op">&lt;</span>T<span class="op">&gt;::</span>value_type<span class="op">&amp;)</span>;</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span> <span class="kw">constexpr</span> complex<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">*(</span><span class="kw">const</span> <span class="kw">typename</span> complex<span class="op">&lt;</span>T<span class="op">&gt;::</span>value_type<span class="op">&amp;</span>, <span class="kw">const</span> complex<span class="op">&lt;</span>T<span class="op">&gt;&amp;)</span>;</span></code></pre></div>
<p>This change does not break any existing code and enables implicit
conversions for <code class="sourceCode cpp">T</code> parameters.</p>
<h1 data-number="6" id="fixing-overloads-with-heterogeneous-types"><span class="header-section-number">6</span> Fixing overloads with
heterogeneous types<a href="#fixing-overloads-with-heterogeneous-types" class="self-link"></a></h1>
<p>If we want to allow operators to work on
<code class="sourceCode cpp">complex</code> class templates with
different value types, we can add additional overloads to handle
that:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><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">typename</span> T<span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em>non-void</em> <span class="op">=</span> <span class="op">(!</span>is_void_v<span class="op">&lt;</span>T<span class="op">&gt;)</span>;</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T, <span class="kw">typename</span> U<span class="op">&gt;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="kw">requires</span><span class="op">(</span>T t, U u<span class="op">)</span> <span class="op">{</span> <span class="op">{</span> t <span class="op">*</span> u <span class="op">}</span> <span class="op">-&gt;</span> <em>non-void</em>; <span class="op">}</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> <span class="kw">operator</span><span class="op">*(</span>complex<span class="op">&lt;</span>T<span class="op">&gt;</span>, complex<span class="op">&lt;</span>U<span class="op">&gt;)</span> <span class="op">-&gt;</span> complex<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>declval<span class="op">&lt;</span>T<span class="op">&gt;()</span> <span class="op">*</span> declval<span class="op">&lt;</span>U<span class="op">&gt;())&gt;</span>;</span></code></pre></div>
<h1 data-number="7" id="impact-on-existing-code"><span class="header-section-number">7</span> Impact on existing code<a href="#impact-on-existing-code" class="self-link"></a></h1>
<p>The proposed solution is fully backward compatible:</p>
<ul>
<li>All existing code continues to compile and behave identically</li>
<li>No performance impact on existing operations</li>
<li>No changes to existing overload resolution for cases that currently
compile</li>
<li>The change only adds new viable overloads for previously ill-formed
expressions</li>
</ul>
<h1 data-number="8" id="implementation-considerations"><span class="header-section-number">8</span> Implementation considerations<a href="#implementation-considerations" class="self-link"></a></h1>
<p>Several standard library implementations have been consulted, and
preliminary implementation shows that the proposed changes can be
implemented without affecting existing optimizations or code
generation.</p>
<h1 data-number="9" id="wording"><span class="header-section-number">9</span> Wording<a href="#wording" class="self-link"></a></h1>
<p>The proposed changes are relative to <span class="citation" data-cites="N5008"><a href="https://wg21.link/n5008" role="doc-biblioref">[N5008]</a></span>.</p>
<h2 data-number="9.1" id="complex.syn"><span class="header-section-number">9.1</span> <a href="https://wg21.link/complex.syn">[complex.syn]</a><a href="#complex.syn" class="self-link"></a></h2>
<p>Modify the declarations in <a href="https://wg21.link/complex.syn">[complex.syn]</a> as follows:</p>
<div>
<div class="sourceCode" id="cb6"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr complex&lt;T&gt; operator+(const complex&lt;T&gt;&amp; lhs, const complex&lt;T&gt;&amp; rhs);</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr complex&lt;T&gt; operator+(const complex&lt;T&gt;&amp; lhs, const <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span></del></span><span class="add" style="color: #006e28"><ins>typename complex<T>::value_type</ins></span>&amp; rhs);</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr complex&lt;T&gt; operator+(const <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span></del></span><span class="add" style="color: #006e28"><ins>typename complex<T>::value_type</ins></span>&amp; lhs, const complex&lt;T&gt;&amp; rhs);</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr complex&lt;T&gt; operator-(const complex&lt;T&gt;&amp; lhs, const complex&lt;T&gt;&amp; rhs);</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr complex&lt;T&gt; operator-(const complex&lt;T&gt;&amp; lhs, const <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span></del></span><span class="add" style="color: #006e28"><ins>typename complex<T>::value_type</ins></span>&amp; rhs);</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr complex&lt;T&gt; operator-(const <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span></del></span><span class="add" style="color: #006e28"><ins>typename complex<T>::value_type</ins></span>&amp; lhs, const complex&lt;T&gt;&amp; rhs);</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr complex&lt;T&gt; operator*(const complex&lt;T&gt;&amp; lhs, const complex&lt;T&gt;&amp; rhs);</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr complex&lt;T&gt; operator*(const complex&lt;T&gt;&amp; lhs, const <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span></del></span><span class="add" style="color: #006e28"><ins>typename complex<T>::value_type</ins></span>&amp; rhs);</span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr complex&lt;T&gt; operator*(const <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span></del></span><span class="add" style="color: #006e28"><ins>typename complex<T>::value_type</ins></span>&amp; lhs, const complex&lt;T&gt;&amp; rhs);</span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr complex&lt;T&gt; operator/(const complex&lt;T&gt;&amp; lhs, const complex&lt;T&gt;&amp; rhs);</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr complex&lt;T&gt; operator/(const complex&lt;T&gt;&amp; lhs, const <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span></del></span><span class="add" style="color: #006e28"><ins>typename complex<T>::value_type</ins></span>&amp; rhs);</span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr complex&lt;T&gt; operator/(const <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span></del></span><span class="add" style="color: #006e28"><ins>typename complex<T>::value_type</ins></span>&amp; lhs, const complex&lt;T&gt;&amp; rhs);</span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr bool operator==(const complex&lt;T&gt;&amp; lhs, const complex&lt;T&gt;&amp; rhs);</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>template&lt;class T&gt; constexpr bool operator==(const complex&lt;T&gt;&amp; lhs, const <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span></del></span><span class="add" style="color: #006e28"><ins>typename complex<T>::value_type</ins></span>&amp; rhs);</span></code></pre></div>
</div>
<h2 data-number="9.2" id="complex.ops"><span class="header-section-number">9.2</span> <a href="https://wg21.link/complex.ops">[complex.ops]</a><a href="#complex.ops" class="self-link"></a></h2>
<p>Modify the function specifications in <a href="https://wg21.link/complex.ops">[complex.ops]</a> to match the
declarations. The semantics remain unchanged, only the parameter types
are modified to enable template argument deduction with implicit
conversions.</p>
<p>For each affected function template, change the parameter type from
<code class="sourceCode cpp"><span class="kw">const</span> T<span class="op">&amp;</span></code>
to <code class="sourceCode cpp"><span class="kw">const</span> <span class="kw">typename</span> complex<span class="op">&lt;</span>T<span class="op">&gt;::</span>value_type<span class="op">&amp;</span></code>
where applicable.</p>
<h2 data-number="9.3" id="feature-test-macro"><span class="header-section-number">9.3</span> Feature test macro<a href="#feature-test-macro" class="self-link"></a></h2>
<p>Add the following feature test macro to <a href="https://wg21.link/version.syn">[version.syn]</a>:</p>
<div>
<div class="sourceCode" id="cb7"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="va">+#define __cpp_lib_complex_implicit_conversions ??????L // also in &lt;complex&gt;</span></span></code></pre></div>
</div>
<h2 data-number="9.4" id="optional-heterogeneous-type-support"><span class="header-section-number">9.4</span> Optional: Heterogeneous type
support<a href="#optional-heterogeneous-type-support" class="self-link"></a></h2>
<p>If the committee decides to support operations between complex
numbers of different types, add the following overloads:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><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">typename</span> T, <span class="kw">typename</span> U<span class="op">&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">+(</span>complex<span class="op">&lt;</span>T<span class="op">&gt;</span>, complex<span class="op">&lt;</span>U<span class="op">&gt;)</span> <span class="op">-&gt;</span> complex<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>declval<span class="op">&lt;</span>T<span class="op">&gt;()</span> <span class="op">+</span> declval<span class="op">&lt;</span>U<span class="op">&gt;())&gt;</span>;</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T, <span class="kw">typename</span> U<span class="op">&gt;</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">-(</span>complex<span class="op">&lt;</span>T<span class="op">&gt;</span>, complex<span class="op">&lt;</span>U<span class="op">&gt;)</span> <span class="op">-&gt;</span> complex<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>declval<span class="op">&lt;</span>T<span class="op">&gt;()</span> <span class="op">-</span> declval<span class="op">&lt;</span>U<span class="op">&gt;())&gt;</span>;</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T, <span class="kw">typename</span> U<span class="op">&gt;</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">*(</span>complex<span class="op">&lt;</span>T<span class="op">&gt;</span>, complex<span class="op">&lt;</span>U<span class="op">&gt;)</span> <span class="op">-&gt;</span> complex<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>declval<span class="op">&lt;</span>T<span class="op">&gt;()</span> <span class="op">*</span> declval<span class="op">&lt;</span>U<span class="op">&gt;())&gt;</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">typename</span> T, <span class="kw">typename</span> U<span class="op">&gt;</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">/(</span>complex<span class="op">&lt;</span>T<span class="op">&gt;</span>, complex<span class="op">&lt;</span>U<span class="op">&gt;)</span> <span class="op">-&gt;</span> complex<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>declval<span class="op">&lt;</span>T<span class="op">&gt;()</span> <span class="op">/</span> declval<span class="op">&lt;</span>U<span class="op">&gt;())&gt;</span>;</span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T, equality_comparable_with<span class="op">&lt;</span>T<span class="op">&gt;</span> U<span class="op">&gt;</span></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>complex<span class="op">&lt;</span>T<span class="op">&gt;</span>, complex<span class="op">&lt;</span>U<span class="op">&gt;)</span>;</span></code></pre></div>
<h1 data-number="10" id="acknowledgements"><span class="header-section-number">10</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>Special thanks and recognition goes to <a href="http://www.epam.com">Epam Systems</a> for supporting Mateusz’s
membership in the ISO C++ Committee and the production of this
proposal.</p>
<h1 data-number="11" id="bibliography"><span class="header-section-number">11</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-N5008" class="csl-entry" role="doc-biblioentry">
[N5008] Thomas Köppe. 2025-03-15. Working Draft, Programming Languages —
C++. <a href="https://wg21.link/n5008"><div class="csl-block">https://wg21.link/n5008</div></a>
</div>
<div id="ref-P0558R1" class="csl-entry" role="doc-biblioentry">
[P0558R1] Billy O’Neal. 2017-03-03. Resolving atomic&lt;T&gt; named base
class inconsistencies. <a href="https://wg21.link/p0558r1"><div class="csl-block">https://wg21.link/p0558r1</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
