<!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="2020-05-13" />
  <title>Feedback on designing the proposed `std::error` type</title>
  <style>
      code{white-space: pre-wrap; color:#05526b}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
      ul.task-list{list-style: none;}
      tt {color:#05526b}
      table {border-collapse: collapse; border:none;}
      td { color:#3b3935; padding-left: 1em; padding-top:0.2em; padding-bottom: 0.2em;}
      pre { background-color: #fafafa; padding: 1em;  };
      .e1 { color:#05526b; font-weight: bold; }
      .e2 { color:#940909; font-weight: bold; }
      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; }
      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;
}
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">Feedback on designing the proposed <code class="sourceCode default">std::error</code> type</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>D2170R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2020-05-13</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>
      Library Evolution Group<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Charles Salvia<br>&lt;<a href="mailto:charles.a.salvia@gmail.com" class="email">charles.a.salvia@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="#abstract"><span class="toc-section-number">1</span> Abstract<span></span></a></li>
<li><a href="#design-constraints"><span class="toc-section-number">2</span> Design constraints<span></span></a>
<ul>
<li><a href="#trivial-relocation"><span class="toc-section-number">2.1</span> Trivial Relocation<span></span></a></li>
<li><a href="#is-stderror-move-only"><span class="toc-section-number">2.2</span> Is std::error move-only?<span></span></a></li>
</ul></li>
<li><a href="#mapping-legacy-error-mechanisms-to-stderror"><span class="toc-section-number">3</span> Mapping “Legacy” Error Mechanisms to std::error<span></span></a>
<ul>
<li><a href="#mapping-stderror_code-to-stderror"><span class="toc-section-number">3.1</span> Mapping std::error_code to std::error<span></span></a></li>
<li><a href="#mapping-dynamic-exceptions-to-stderror"><span class="toc-section-number">3.2</span> Mapping dynamic exceptions to std::error<span></span></a></li>
<li><a href="#posix-generic"><span class="toc-section-number">3.3</span> POSIX != generic<span></span></a></li>
</ul></li>
<li><a href="#the-submitted-stderror-implementation"><span class="toc-section-number">4</span> The submitted std::error implementation<span></span></a>
<ul>
<li><a href="#differences-with-the-status_code-library-implementation-proposed-in-p1028"><span class="toc-section-number">4.1</span> Differences with the status_code library implementation proposed in [P1028]<span></span></a></li>
<li><a href="#a-minimal-sketch-of-an-stderror-specification"><span class="toc-section-number">4.2</span> A minimal sketch of an std::error specification<span></span></a></li>
</ul></li>
<li><a href="#bibliography"><span class="toc-section-number">5</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="abstract"><span class="header-section-number">1</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p><span class="citation" data-cites="P0709">[<a href="#ref-P0709" role="doc-biblioref">P0709R4</a>]</span> proposes <code class="sourceCode default">std::error</code> as a mechanism for supporting deterministic static exceptions, as well as a more powerful successor to <code class="sourceCode default">std::error_code</code>. I’ve implemented the proposed <code class="sourceCode default">std::error</code>, including support for treating <code class="sourceCode default">std::exception_ptr</code> as a <code class="sourceCode default">TriviallyRelocatable</code> type that can be transported via an <code class="sourceCode default">std::error</code> object without performing an allocation. In this paper I provide feedback on the overall design of <code class="sourceCode default">std::error</code>, particularly with regard to how it might map to “legacy” error mechanisms such as dynamic exceptions and/or <code class="sourceCode default">std::error_code</code>, and also provide some discussion and rationale around design decisions and trade-offs I made while implementing <code class="sourceCode default">std::error</code> that differ from the current <code class="sourceCode default">status_code</code> based implementation proposed in <span class="citation" data-cites="P1028">[<a href="#ref-P1028" role="doc-biblioref">P1028R3</a>]</span>.</p>
<p>This paper does not propose anything fundamentally different from <span class="citation" data-cites="P0709">[<a href="#ref-P0709" role="doc-biblioref">P0709R4</a>]</span>, but merely explores certain design considerations and trade-offs that surface when implementing <code class="sourceCode default">std::error</code> and suggests what a minimal specification should probably contain based on actual implementation experience, while also discussing considerations that arise when attempting to map <code class="sourceCode default">std::error</code> to “legacy” error mechanisms such as dynamic exceptions and <code class="sourceCode default">std::error_code</code>. Finally, this paper is focused only on the design and implementation of the <code class="sourceCode default">std::error</code> type and how it maps to existing error facilities - this paper does <em>not</em> address the larger issue of deterministic static exceptions.</p>
The implementation of <code class="sourceCode default">std::error</code> discussed here is available at:
<blockquote>
<p>Repos link: <a href="https://github.com/charles-salvia/std_error">github.com/charles-salvia/std_error</a></p>
<p>All-in-one header-only link: <a href="https://github.com/charles-salvia/std_error/blob/master/all_in_one.hpp">github.com/charles-salvia/std_error/blob/master/all_in_one.hpp</a></p>
Example usage/godbolt link: <a href="https://godbolt.org/z/8o1Yg6">godbolt.org/z/8o1Yg6</a>
</blockquote>
<p>The implementation requires at least C++14. It has been tested on GCC 4.9.2 to GCC 10, Clang 4 thru Clang 10, and MSVC 19.14 thru 19.24.</p>
<h1 data-number="2" id="design-constraints"><span class="header-section-number">2</span> Design constraints<a href="#design-constraints" class="self-link"></a></h1>
<h2 data-number="2.1" id="trivial-relocation"><span class="header-section-number">2.1</span> Trivial Relocation<a href="#trivial-relocation" class="self-link"></a></h2>
<p>A key feature of the proposed <code class="sourceCode default">std::error</code> type is that an instance should be no larger than two pointers. An <code class="sourceCode default">std::error</code> therefore consists of a pointer-sized type-erased object, and a constant pointer to a domain instance. This is similar to <code class="sourceCode default">std::error_code</code>, where we have an integral type code along with a pointer to an <code class="sourceCode default">std::error_category</code>, except <code class="sourceCode default">std::error</code> contains a type-erased object that could potentially represent any arbitrarily rich data. It’s up to the <code class="sourceCode default">error_domain</code> object to decide how to statically cast the type-erased data to the appropriate type.</p>
<p>One important requirement of any type <code class="sourceCode default">T</code> that is to be type-erased and stored within an <code class="sourceCode default">std::error</code> is that <code class="sourceCode default">T</code> must be <code class="sourceCode default">TriviallyRelocatable</code>, meaning essentially that move-constructing an instance of <code class="sourceCode default">T</code> must be functionally equivalent to simply performing a bitwise copy and then replacing the moved-from instance with <code class="sourceCode default">T{}</code>. Both <code class="sourceCode default">std::unique_ptr</code> and <code class="sourceCode default">std::shared_ptr</code> could fit this requirement conceptually, as could <code class="sourceCode default">std::exception_ptr</code>.</p>
<p>An <code class="sourceCode default">std::error</code> object could then easily contain either an integral-type error code, or arbitrarily rich information passed in as a type-erased smart pointer which would be <em>move-relocated</em> into the pointer-sized storage contained in the <code class="sourceCode default">std::error</code> object. An <code class="sourceCode default">std::exception_ptr</code>, if implemented such that it is no larger than a raw pointer, could also be transported efficiently in an <code class="sourceCode default">std::error</code>.</p>
<p>However, being able to transport a type-erased smart pointer such as <code class="sourceCode default">std::exception_ptr</code> immediately brings up certain design decisions that need to be considered up-front. For example, as a type-erasing transport for arbitrary <code class="sourceCode default">TriviallyRelocatable</code> types, <code class="sourceCode default">std::error</code> must at the very least have access to a polymorphic destructor function that can invoke the destructor of the erased type. If we limit <code class="sourceCode default">std::error</code> itself to being <code class="sourceCode default">TriviallyRelocatable</code> with a deleted copy constructor, we do not need to provide any additional polymorphic functions to manage ownership of the erased type, apart from the destructor.</p>
<p>For example, in order to transport a <code class="sourceCode default">unique_ptr</code> in an <code class="sourceCode default">std::error</code>, we would <em>move-relocate</em> the <code class="sourceCode default">unique_ptr</code> instance into type-erased storage, and then simply bitwise-copy the type-erased storage an arbitrary number of times until the last move-constructed instance is destructed, at which point we’d need to call a polymorphic destructor that has knowledge of the erased type (implemented perhaps as a virtual function in the <code class="sourceCode default">error_domain</code>). We can set the internal <code class="sourceCode default">error_domain</code> pointer of a moved-from <code class="sourceCode default">std::error</code> instance to <code class="sourceCode default">nullptr</code> to disable destructors of moved-from error objects. This is how the <code class="sourceCode default">status_code</code> based implementation of <code class="sourceCode default">std::error</code> proposed in <span class="citation" data-cites="P1028">[<a href="#ref-P1028" role="doc-biblioref">P1028R3</a>]</span> is implemented. This design also requires that <code class="sourceCode default">std::error</code> itself is move-only.</p>
<h2 data-number="2.2" id="is-stderror-move-only"><span class="header-section-number">2.2</span> Is std::error move-only?<a href="#is-stderror-move-only" class="self-link"></a></h2>
<p>Should <code class="sourceCode default">std::error</code> be required to be move-only? The original proposal <span class="citation" data-cites="P0709">[<a href="#ref-P0709" role="doc-biblioref">P0709R4</a>]</span> doesn’t explicitly say that <code class="sourceCode default">std::error</code> is move-only; rather, it only specifies that <code class="sourceCode default">std::error</code> should be trivially relocatable. However, this doesn’t necessarily mean <code class="sourceCode default">std::error</code> must be move-only. A generic copy constructor for some erased type <code class="sourceCode default">T</code> could be safely implemented by copy-constructing a temporary, and then move-relocating it into the destination storage. Regardless, the current <code class="sourceCode default">status_code</code> based implementation of <code class="sourceCode default">std::error</code> proposed in <span class="citation" data-cites="P1028">[<a href="#ref-P1028" role="doc-biblioref">P1028R3</a>]</span> is indeed move-only, but provides a <code class="sourceCode default">clone()</code> function for explicitly copying an error instance.</p>
<p>The implementation of <code class="sourceCode default">std::error</code> submitted here is both trivially-relocatable and copy-constructible. (Note that many trivially relocatable types are copy-constructible, but not <em>trivially</em> copy-constructible, such as <code class="sourceCode default">std::shared_ptr</code>.) Implementing a copy-constructible version of <code class="sourceCode default">std::error</code> requires that we call the copy-constructor of the type-erased object each time the <code class="sourceCode default">std::error</code> object itself is copied. This can be efficiently implemented by providing the <code class="sourceCode default">error_domain</code> instance with three function pointers - a copy constructor, move constructor, and destructor. (Again, the copy construction would need to be implemented in terms of a copy, followed by a move-relocate.) Error domains that use trivially-copyable types, such as enums or integral types, can set the function pointers to <code class="sourceCode default">nullptr</code>. Since error domains are expected to be <code class="sourceCode default">constexpr</code>, the call to the copy/move-constructor or destructor can be optimized out, and since statically thrown errors are essentially return-by-value, copying would be elided very often anyway.</p>
<p>Regardless, it remains an open question whether <code class="sourceCode default">std::error</code> should be copy-constructible. As a general replacement for both <code class="sourceCode default">std::error_code</code> as well as dynamic exceptions, it seems we should default to allowing <code class="sourceCode default">std::error</code> to support copy construction unless there is a very compelling reason not to. Both <code class="sourceCode default">std::error_code</code> and <code class="sourceCode default">std::exception_ptr</code> are copy-constructible, and there seems no reason to limit <code class="sourceCode default">std::error</code> to being move-only, apart from the requirement that any type-erased object used with <code class="sourceCode default">std::error</code> would need to be trivially-relocatable <em>and</em> copy-constructible. This rules out <code class="sourceCode default">std::unique_ptr</code>, but allows <code class="sourceCode default">std::exception_ptr</code>.</p>
<p>As a general mechanism for conveniently transporting arbitrary data via a copy-constructible <code class="sourceCode default">std::error</code>, it would be nice to be able to easily store a type-erased reference counted smart pointer. Unfortunately, we cannot directly store an <code class="sourceCode default">std::shared_ptr</code> in the single-pointer-sized storage provided by <code class="sourceCode default">std::error</code>, since a <code class="sourceCode default">std::shared_ptr</code> implementation typically requires at least 2 pointers due to aliasing support <span class="citation" data-cites="N2351">[<a href="#ref-N2351" role="doc-biblioref">N2351</a>]</span>. Rather, we would need a simpler reference counting smart pointer type, perhaps using intrusive reference counting, so that it could fit into single-pointer-sized storage. (The implementation presented here includes a reference-counting intrusive smart pointer to demonstrate transporting arbitrary data via an <code class="sourceCode default">std::error</code>). Note that we don’t have the same problem with <code class="sourceCode default">std::exception_ptr</code>, which can be implemented as a move-relocatable type with single-pointer size, and in fact is single-pointer-size in mainstream implementations such as <span class="citation" data-cites="libstdcpp">[<a href="#ref-libstdcpp" role="doc-biblioref">GNU libstdc++</a>]</span>.</p>
<h1 data-number="3" id="mapping-legacy-error-mechanisms-to-stderror"><span class="header-section-number">3</span> Mapping “Legacy” Error Mechanisms to std::error<a href="#mapping-legacy-error-mechanisms-to-stderror" class="self-link"></a></h1>
<h2 data-number="3.1" id="mapping-stderror_code-to-stderror"><span class="header-section-number">3.1</span> Mapping std::error_code to std::error<a href="#mapping-stderror_code-to-stderror" class="self-link"></a></h2>
<p>The original proposal <span class="citation" data-cites="P0709">[<a href="#ref-P0709" role="doc-biblioref">P0709R4</a>]</span> discusses mapping standard dynamic exception types to <code class="sourceCode default">std::error</code>, and also implies that <code class="sourceCode default">std::errc</code> enums will be inherited from <code class="sourceCode default">&lt;system_error&gt;</code> to represent a “generic” domain of errors. However, it doesn’t discuss mapping an arbitrary <code class="sourceCode default">std::error_code</code> to an <code class="sourceCode default">std::error</code> object. Presumably, in the interest of easing adoption of <code class="sourceCode default">std::error</code>, we would want any possible <code class="sourceCode default">std::error_code</code> to be convertible to an <code class="sourceCode default">std::error</code>.</p>
<p>We can efficiently convert <code class="sourceCode default">std::error_code</code> objects that use standard error categories to an <code class="sourceCode default">std::error</code> by simply storing <code class="sourceCode default">ErrorCodeEnum</code>s in <code class="sourceCode default">std::error</code> storage and providing matching <code class="sourceCode default">error_domain</code> objects for each standard <code class="sourceCode default">error_category</code>. Perhaps we would have a <code class="sourceCode default">generic_domain</code> that represents error values using <code class="sourceCode default">std::errc</code>, exactly like <code class="sourceCode default">std::generic_category()</code> does now.</p>
<p>However, we cannot efficiently represent an arbitrary <code class="sourceCode default">std::error_code</code> object that may potentially have any arbitrary user-defined <code class="sourceCode default">error_category</code>. We need at least 2 pointers worth of storage to represent an arbitrary <code class="sourceCode default">std::error_code</code> - one for the code itself and the other for a pointer to the <code class="sourceCode default">error_category</code>. Since we only have one pointer worth of storage in an <code class="sourceCode default">std::error</code>, we’d need a heap allocation to map an arbitrary <code class="sourceCode default">std::error_code</code> to an <code class="sourceCode default">std::error</code>. The implementation submitted here provides matching error domains for standard categories (such as <code class="sourceCode default">std::generic_category</code>), and uses heap allocation managed by a reference counted pointer to store <code class="sourceCode default">std::error_code</code>s with custom categories in an <code class="sourceCode default">std::error</code> object.</p>
<p>Finally, an <code class="sourceCode default">std::error_code</code> may potentially store a zero-value <code class="sourceCode default">ErrorCodeEnum</code> to represent “not an error”, whereas an <code class="sourceCode default">std::error</code> <em>always</em> represents an error. If we want to provide mappings between <code class="sourceCode default">std::error_code</code> and <code class="sourceCode default">std::error</code> we essentially have two choices to handle “not an error” error codes. We can either consider it Undefined Behavior (in the same way that throwing a null <code class="sourceCode default">std::exception_ptr</code> is undefined behavior), or more preferably, we map it to a special error code/domain that represents an invalid error, such as <code class="sourceCode default">errc::bad_error</code>.</p>
<h2 data-number="3.2" id="mapping-dynamic-exceptions-to-stderror"><span class="header-section-number">3.2</span> Mapping dynamic exceptions to std::error<a href="#mapping-dynamic-exceptions-to-stderror" class="self-link"></a></h2>
<p>The original proposal <span class="citation" data-cites="P0709">[<a href="#ref-P0709" role="doc-biblioref">P0709R4</a>]</span> discusses mapping standard dynamic exception types to <code class="sourceCode default">std::error</code>. Note that when we talk about mapping a dynamic exception to an <code class="sourceCode default">std::error</code>, we’re mostly talking about doing so in the context of a weak-equality (semantic-equivalence) comparison. An <code class="sourceCode default">std::error</code> can <em>directly</em> store an <code class="sourceCode default">std::exception_ptr</code>, so there’s no need to perform any “mapping” at all for the purposes of simply converting a dynamic exception to an <code class="sourceCode default">std::error</code>. However, we probably want to be able to use the <code class="sourceCode default">==</code> operator to perform a semantic comparison with an <code class="sourceCode default">std::error</code> against a set of generic enums such as <code class="sourceCode default">std::errc</code>.</p>
<p>In this context, it would be useful to map, for example, <code class="sourceCode default">std::bad_alloc</code> to <code class="sourceCode default">std::errc::not_enough_memory</code>, so that a dynamic exception converted to an <code class="sourceCode default">std::error</code> can be tested for weak-equality or semantic equivalence. The original proposal mentions the need to standardize these mappings.</p>
<p>It turns out that providing mappings from the set of standard C++ dynamic exceptions to the set of <code class="sourceCode default">std::errc</code> enums is not easy to do in a way that consistently results in meaningful error translations. At first glance it may seem promising: we can map <code class="sourceCode default">std::invalid_argument</code> to <code class="sourceCode default">std::errc::invalid_argument</code> of course, <code class="sourceCode default">std::bad_alloc</code> to <code class="sourceCode default">std::errc::not_enough_memory</code>, and <code class="sourceCode default">std::domain_error</code> to <code class="sourceCode default">std::errc::argument_out_of_domain</code>, to name a few obvious mappings.</p>
<p>The <a href="https://ned14.github.io/status-code">documentation</a> for the <code class="sourceCode default">status_code</code> based implementation of <code class="sourceCode default">std::error</code> suggests the following mappings:</p>
<table>
<tr>
<td>
<tt>std::invalid_argument</tt>
</td>
<td>
→
</td>
<td>
<tt>errc::invalid_argument</tt>
</td>
</tr>
<tr>
<td>
<tt>std::domain_error</tt>
</td>
<td>
→
</td>
<td>
<tt>errc::argument_out_of_domain</tt>
</td>
</tr>
<tr>
<td>
<tt>std::length_error</tt>
</td>
<td>
→
</td>
<td>
<tt>errc::argument_list_too_long</tt>
</td>
</tr>
<tr>
<td>
<tt>std::out_of_range</tt>
</td>
<td>
→
</td>
<td>
<tt>errc::result_out_of_range</tt>
</td>
</tr>
<tr>
<td>
<tt>std::logic_error</tt>
</td>
<td>
→
</td>
<td>
<tt>errc::invalid_argument</tt>
</td>
</tr>
<tr>
<td>
<tt>std::overflow_error</tt>
</td>
<td>
→
</td>
<td>
<tt>errc::value_too_large</tt>
</td>
</tr>
<tr>
<td>
<tt>std::range_error</tt>
</td>
<td>
→
</td>
<td>
<tt>errc::result_out_of_range</tt>
</td>
</tr>
<tr>
<td>
<tt>std::runtime_error</tt>
</td>
<td>
→
</td>
<td>
<tt>errc::resource_unavailable_try_again</tt>
</td>
</tr>
<tr>
<td>
<tt>std::bad_alloc</tt>
</td>
<td>
→
</td>
<td>
<tt>errc::not_enough_memory</tt>
</td>
</tr>
</table>
<p>The implementation submitted here suggests a slightly modified mapping. However, both mappings are incomplete, reductive, and contain some highly questionable translations such as <code class="sourceCode default">std::runtime_error</code> → <code class="sourceCode default">errc::resource_unavailable_try_again</code>. Additionally, this only provides mappings for standard exceptions included under <code class="sourceCode default">&lt;stdexcept&gt;</code>. But how would we map something like <code class="sourceCode default">std::regex_error</code>, <code class="sourceCode default">std::bad_cast</code> or <code class="sourceCode default">std::bad_variant_access</code>? In the proposed mapping above, an <code class="sourceCode default">std::regex_error</code>, which inherits from <code class="sourceCode default">std::runtime_error</code>, would be mapped to <code class="sourceCode default">errc::resource_unavailable_try_again</code>, which conveys no useful semantic information about the original error and is probably misleading or confusing to anyone familiar with the POSIX error codes <code class="sourceCode default">EAGAIN</code> or <code class="sourceCode default">EWOULDBLOCK</code>.</p>
<h2 data-number="3.3" id="posix-generic"><span class="header-section-number">3.3</span> POSIX != generic<a href="#posix-generic" class="self-link"></a></h2>
<p>The root of the problem here is that we are probably wrongly assuming that the <code class="sourceCode default">std::errc</code> enums really constitute a set of truly “generic” error codes. This faulty assumption is understandable since, after all, these error codes are lifted from POSIX and are designed to provide portability, which is why <code class="sourceCode default">std::errc</code> codes are used with <code class="sourceCode default">std::generic_category</code> in <code class="sourceCode default">&lt;system_error&gt;</code>. But the reality is the POSIX error codes that the <code class="sourceCode default">std::errc</code> enums map to were devised with the goal of defining a set of generic error codes that might usefully map to the sort of errors that an <em>Operating System API</em> might produce. (And not just any OS API really, but specifically a UNIX-flavored OS API.) As a set of generic <em>system</em> error codes, POSIX seems to have provided a useful set of mostly portable codes for <code class="sourceCode default">&lt;system_error&gt;</code> to adopt. But again these codes were lifted from <em>Operating System API</em> errors - <em>not</em> generic application errors. These codes include error conditions for circumstances that are completely beyond the scope of the current C++ standard, such as <code class="sourceCode default">std::errc::broken_pipe</code> and <code class="sourceCode default">std::errc::inappropriate_io_control_operation</code>.</p>
<p>Of course, the intention of <code class="sourceCode default">&lt;system_error&gt;</code> was never to provide a set of truly <em>generic</em> error codes - it was to provide a set of generic <em>system</em> error codes that could be portably communicated in standard C++. In that capacity, using the POSIX error codes for <code class="sourceCode default">std::errc</code> was a reasonable choice. But regardless, <code class="sourceCode default">&lt;system_error&gt;</code> is not meant to provide a set of “generic” application-level error conditions, and so this family of error codes is probably not suitable for mapping <em>application-level</em> errors, the very type of errors that standard C++ dynamic exceptions represent. A hypothetical set of error codes that represent truly generic <em>application</em> errors would look more like what we get in <code class="sourceCode default">&lt;stdexcept&gt;</code>: maybe something like <code class="sourceCode default">generic_errc::runtime_error</code>, <code class="sourceCode default">generic_errc::out_of_range</code>, <code class="sourceCode default">generic_errc::size_error</code>, etc. This is the same sort of “generic error” taxonomy found in typical standard exception libraries across many languages, such as Python’s builtin <code class="sourceCode default">RuntimeError</code>, <code class="sourceCode default">OverflowError</code>, <code class="sourceCode default">IndexError</code>, etc. A set of generic error codes mapping to C++ exceptions should probably look more like this and less like something that includes <code class="sourceCode default">inappropriate_io_control_operation</code> and <code class="sourceCode default">bad_file_descriptor</code>.</p>
<p>In fact, Boost.Python appears to have better luck mapping standard <a href="https://github.com/boostorg/python/blob/develop/src/errors.cpp#L32">C++ exceptions to Python exceptions</a>, since the error domain (generic application runtime errors) is essentially the same. But <code class="sourceCode default">std::errc</code> represents a <em>different</em> error domain - the error domain of a UNIX-derived OS API, with pipes, file descriptors and <code class="sourceCode default">ioctl</code> calls. To the extent that the concerns of an Operating System API overlap with the concerns of a user-level application (mostly within the domain of argument validation) we can find meaningful mappings from <code class="sourceCode default">&lt;system_error&gt;</code> to standard C++ exceptions. But beyond that it becomes a stretch, with very little semantic information conveyed by the error code.</p>
<p>While <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_03">POSIX.1</a> attaches certain broad semantics to each error macro, the majority of these codes were clearly designed around common failures that may occur within a networking stack or file system, or through exhaustion of OS resources or incorrect user space usage of an OS API or service. Apart from the C++ Networking TS or Filesystem library, only a few codes out of the 80 or so codes defined in POSIX.1 are applicable to the same conceptual error domain as most standard C++ exceptions. These probably include <code class="sourceCode default">EINVAL</code>, <code class="sourceCode default">ERANGE</code>, <code class="sourceCode default">EDOM</code>, <code class="sourceCode default">E2BIG</code>, and <code class="sourceCode default">ENOMEM</code>. These alone are clearly insufficient to create meaningful mappings across all standard C++ exceptions. Note there is not even a POSIX code that clearly maps to “index out of bounds”: we’d have to settle for <code class="sourceCode default">EINVAL</code> which is reductive, or else abuse the intended meaning of <code class="sourceCode default">ERANGE</code>.</p>
<p>Since <code class="sourceCode default">std::error</code> is clearly meant as “one error type to rule them all” - as the eventual successor of both <code class="sourceCode default">std::error_code</code> and dynamic exceptions in general, it seems we clearly need something a lot broader than <code class="sourceCode default">&lt;system_error&gt;</code> to use as a family of “generic” error codes. The current <code class="sourceCode default">status_code</code> based implementation of <code class="sourceCode default">std::error</code> proposed in <span class="citation" data-cites="P1028">[<a href="#ref-P1028" role="doc-biblioref">P1028R3</a>]</span> reuses the <code class="sourceCode default">std::errc</code> codes (with one slight modification), and expects all error domains to be able to map errors to one of these “generic” codes. But for many error domains there simply isn’t anything useful in POSIX to map to. How again do we map an <code class="sourceCode default">std::regex_error</code> to a POSIX code? Do we just use <code class="sourceCode default">errc::invalid_argument</code> or something and give up on providing any meaningful mapping?</p>
<p>I would suggest two things: firstly, to review the idea that every possible <code class="sourceCode default">std::error</code> domain is to be expected to map to some “universal” set of generic error codes in the first place. I argue that this requirement is likely to be impractical for many error domains, and if enforced would simply lead to many useless error mappings that convey next to zero actual information about the semantics of the original error.</p>
<p>Secondly, if we do want to provide something like a set of “universal” generic error codes that any error domain could feasibly map to, <em>and</em> if we also want to have a set of error codes available that enables useful weak-equality comparisons with an <code class="sourceCode default">std::error</code> that stores an <code class="sourceCode default">std::exception_ptr</code>, we would probably want to define a new, more universal set of error code enums that are not specifically designed for Operating System API errors. This set of error codes should more closely map to the set of exceptions defined in <code class="sourceCode default">&lt;stdexcept&gt;</code> and other standard headers, and include codes for C++-specific error conditions such as an invalid <code class="sourceCode default">dynamic_cast</code>.</p>
<p>The approach submitted here (and used in the submitted implementation) is to begin by defining a set of error code enums specifically meant to represent all standard dynamic exceptions. Note that many standard exceptions are de-facto equivalent to an error code enum, in the sense that they convey no information other then their <em>type</em> and a static message. For example, <code class="sourceCode default">std::bad_variant_access</code> or <code class="sourceCode default">std::bad_cast</code> (or any other exception type that provides only a default constructor, copy constructor, and static <code class="sourceCode default">what()</code> message), convey no information beyond their type and the static message associated with their type. Thus they are representable as semantically equivalent error codes with zero loss of information. Other exception types (such as <code class="sourceCode default">std::runtime_error</code>) take a per-instance message string, and so cannot be represented as an error code without information loss. However, since <code class="sourceCode default">std::error</code> can store an <code class="sourceCode default">std::exception_ptr</code> which can convey the per-instance message, there is no problem here. Regardless, mapping all standard exceptions to a special set of dynamic exception error codes may be useful in bridging dynamic exceptions and static errors, especially with regard to weak-equality testing. These dynamic exception error code enums may look something like the following:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1"></a>    <span class="kw">enum</span> <span class="kw">class</span> dynamic_exception_errc</span>
<span id="cb1-2"><a href="#cb1-2"></a>    <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3"></a>        runtime_error,</span>
<span id="cb1-4"><a href="#cb1-4"></a>        domain_error,</span>
<span id="cb1-5"><a href="#cb1-5"></a>        invalid_argument,</span>
<span id="cb1-6"><a href="#cb1-6"></a>        length_error,</span>
<span id="cb1-7"><a href="#cb1-7"></a>        out_of_range,</span>
<span id="cb1-8"><a href="#cb1-8"></a>        range_error,</span>
<span id="cb1-9"><a href="#cb1-9"></a>        overflow_error,</span>
<span id="cb1-10"><a href="#cb1-10"></a>        underflow_error,</span>
<span id="cb1-11"><a href="#cb1-11"></a>        system_error,</span>
<span id="cb1-12"><a href="#cb1-12"></a>        bad_alloc,</span>
<span id="cb1-13"><a href="#cb1-13"></a>        bad_array_new_length,</span>
<span id="cb1-14"><a href="#cb1-14"></a>        bad_optional_access,</span>
<span id="cb1-15"><a href="#cb1-15"></a>        bad_typeid,</span>
<span id="cb1-16"><a href="#cb1-16"></a>        bad_any_cast,</span>
<span id="cb1-17"><a href="#cb1-17"></a>        regex_error,</span>
<span id="cb1-18"><a href="#cb1-18"></a>        bad_cast,</span>
<span id="cb1-19"><a href="#cb1-19"></a>        bad_weak_ptr,</span>
<span id="cb1-20"><a href="#cb1-20"></a>        bad_exception,</span>
<span id="cb1-21"><a href="#cb1-21"></a>        bad_variant_access,</span>
<span id="cb1-22"><a href="#cb1-22"></a>        unspecified_exception</span>
<span id="cb1-23"><a href="#cb1-23"></a>    <span class="op">}</span>;</span></code></pre></div>
<p>This would specifically map dynamic exceptions to a set of error codes that could be usefully employed to test for weak equality. On top of this, I would also suggest providing a set of truly “generic” application level error code enums, perhaps using the enum class <code class="sourceCode default">generic_errc</code>. Ideally, <code class="sourceCode default">std::errc</code> would have been named <code class="sourceCode default">std::posix_errc</code> - however, again <code class="sourceCode default">&lt;system_error&gt;</code> was designed foremost within the context of the Operating System error domain, and was probably not initially conceived of with generic application level error codes in mind.</p>
<p>Defining a set of generic application level error codes is beyond the scope of this paper, and the submitted implementation does not even attempt this. However, a hypothetical set of generic error codes would probably look something like the above list of dynamic_exception error codes. As such, a better approach may simply be to get rid of the idea of a separate <code class="sourceCode default">dynamic_exception_errc</code> set of codes and just make these the generic codes. Domains that have more specific error-reporting requirements, such as <code class="sourceCode default">std::regex_error</code> could also implement separate <code class="sourceCode default">error_domain</code>s.</p>
<h1 data-number="4" id="the-submitted-stderror-implementation"><span class="header-section-number">4</span> The submitted std::error implementation<a href="#the-submitted-stderror-implementation" class="self-link"></a></h1>
<p>The submitted <code class="sourceCode default">std::error</code> implementation is not meant to represent a formal proposal, but to serve as a hopefully useful contribution and alternative reference implementation of <code class="sourceCode default">std::error</code> that can assist with design discussions going forward. It can also serve as an initial sketch of a specification for <code class="sourceCode default">std::error</code> and associated types. The submitted implementation supports all the requirements laid out in <span class="citation" data-cites="P0709">[<a href="#ref-P0709" role="doc-biblioref">P0709R4</a>]</span>, namely:</p>
<ol type="1">
<li><code class="sourceCode default">std::error</code> always represents a failure</li>
<li><code class="sourceCode default">sizeof(std::error) == sizeof(std::intptr_t) * 2</code></li>
<li>It uses <code class="sourceCode default">constexpr</code> error_domain discriminants to implement polymorphic behavior</li>
<li>It is able to represent all causes of failure within the C++ standard library</li>
<li>It is type-erased, allocation-free, and trivially-relocatable</li>
<li>It can be used in a header-only library (unlike <code class="sourceCode default">std::error_category</code>)</li>
<li>It has a <code class="sourceCode default">==</code> operator that provides weak-equality comparison (semantic-equivalence)</li>
</ol>
<p>The submitted implementation includes an opt-in <code class="sourceCode default">is_trivially_relocatable</code> trait that enables <code class="sourceCode default">std::exception_ptr</code> to be stored directly within an <code class="sourceCode default">std::error</code> without an additional allocation (provided the implementation of <code class="sourceCode default">std::exception_ptr</code> is only one pointer in size, such as the <span class="citation" data-cites="libstdcpp">[<a href="#ref-libstdcpp" role="doc-biblioref">GNU libstdc++</a>]</span> implementation shipped with GCC).</p>
<h2 data-number="4.1" id="differences-with-the-status_code-library-implementation-proposed-in-p1028"><span class="header-section-number">4.1</span> Differences with the status_code library implementation proposed in [P1028]<a href="#differences-with-the-status_code-library-implementation-proposed-in-p1028" class="self-link"></a></h2>
<p>The submitted implementation differs with the current <code class="sourceCode default">status_code</code> based implementation proposed in <span class="citation" data-cites="P1028">[<a href="#ref-P1028" role="doc-biblioref">P1028R3</a>]</span> as follows:</p>
<ol type="1">
<li>This implementation is a stand-alone implementation of <code class="sourceCode default">std::error</code> - it does not implement any larger status code or error code library</li>
<li>This implementation makes <code class="sourceCode default">std::error</code> copy-constructible instead of move-only</li>
<li>This implementation does not require all error domains to be able to map errors to a universal “generic” error code</li>
<li>For the purpose of providing error code enums used for weak-equality comparisons with <code class="sourceCode default">std::error</code> objects transporting a thrown dynamic exception, this implementation defines a new <code class="sourceCode default">dynamic_exception_errc</code> enum class. (It also supports semantic comparison with <code class="sourceCode default">std::errc</code> such that, e.g. a thrown <code class="sourceCode default">std::invalid_argument</code> will compare semantically equivalent to an <code class="sourceCode default">std::errc::invalid_argument</code>, but for the reasons discussed above I consider <code class="sourceCode default">std:errc</code> to be inadequate for serving as a set of universal generic error codes.)</li>
<li>Error domain ID’s are 128-bit integers instead of 64-bit. With 64-bit, the chance of a collision approaches 50% when you reach about ~4 billion randomly generated error domain IDs. While it’s obviously absurdly unlikely any single application will ever have that many error domains, consider a future where distributed applications transmit serialized <code class="sourceCode default">std::error</code> objects over the wire. In this case domain IDs should be globally unique, so 128-bit is probably more appropriate.</li>
</ol>
<p>With regard to the weak-equality comparison algorithm, this implementation submits a simpler algorithm than the algorithm implemented in <span class="citation" data-cites="P1028">[<a href="#ref-P1028" role="doc-biblioref">P1028R3</a>]</span>. The algorithm implemented in <span class="citation" data-cites="P1028">[<a href="#ref-P1028" role="doc-biblioref">P1028R3</a>]</span> is as follows:</p>
<blockquote>
<pre>
Given: <tt>error</tt> <tt><b>E1</b></tt> with <tt>error_domain</tt> <tt><b>D1</b></tt>, and <tt>error</tt> <span class="e2">E2</span> with <tt>error_domain</tt> <span class="e2">D2</span>

If both <tt><b>D1</b></tt> and <span class="e2">D2</span> are non-null:
   If <tt><b>D1</b></tt>.<tt>WeakEqualityCompare</tt>(<tt><b>E1</b></tt>, <span class="e2">E2</span>): return <tt>true</tt>
   Else If <span class="e2">D2</span>.<tt>WeakEqualityCompare</tt>(<span class="e2">E2</span>, <tt><b>E1</b></tt>): return <tt>true</tt>
   Else:
      Convert <span class="e2">E2</span> to <tt>GenericCode</tt> <span class="e2">G2</span>
      If <tt><b>D1</b></tt>.<tt>WeakEqualityCompare</tt>(<tt><b>E1</b></tt>, <span class="e2">G2</span>): return <tt>true</tt>

      Convert <tt><b>E1</b></tt> to <tt>GenericCode</tt> <tt><b>G1</b></tt>
      If <span class="e2">D2</span>.<tt>WeakEqualityCompare</tt>(<span class="e2">E2</span>, <tt><b>G1</b></tt>): return <tt>true</tt>

return <tt>true</tt> if both <tt><b>D1</b></tt> and <span class="e2">D2</span> are null
</pre>
</blockquote>
<p>Note this algorithm requires error domains to implement conversion from some arbitrary error type to a universal set of “generic” errors (specified in <span class="citation" data-cites="P1028">[<a href="#ref-P1028" role="doc-biblioref">P1028R3</a>]</span> as identical to the POSIX error codes defined in <code class="sourceCode default">&lt;system_error&gt;</code>). The implementation submitted here does not require that all error types must be representable by a single set of generic codes. I have argued that this is very likely impractical for certain error domains, and if enforced would merely lead to many useless mappings to “generic” codes that convey close to zero information about the semantics of the original error.</p>
<p>Additionally, the implementation submitted here does not permit an error object to have a <code class="sourceCode default">nullptr</code> for an error_domain. In <span class="citation" data-cites="P1028">[<a href="#ref-P1028" role="doc-biblioref">P1028R3</a>]</span>, <code class="sourceCode default">error</code> objects are move-only and therefore a “moved-from” <code class="sourceCode default">error</code> has a null domain pointer. However, <code class="sourceCode default">error</code> objects in this implementation are copy-constructible; errors that transport non-trivially-copyable or non-trivially-movable types will provide polymorphic move and copy constructors. It is up to the domain-specific move constructor to decide how to represent a “moved-from” type-erased error value internally. Therefore, there is no reason to allow an error object to contain a null domain pointer.</p>
<p>With null domain pointers disallowed, and without the requirement that all error domains provide a mapping to a set of universal generic error codes, the weak-equality comparison algorithm implemented here is simply:</p>
<blockquote>
<pre>
Given: <tt>error</tt> <tt><b>E1</b></tt> with <tt>error_domain</tt> <tt><b>D1</b></tt>, and <tt>error</tt> <span class="e2">E2</span> with <tt>error_domain</tt> <span class="e2">D2</span>

If <tt><b>D1</b></tt>.<tt>WeakEqualityCompare</tt>(<tt><b>E1</b></tt>, <span class="e2">E2</span>): return <tt>true</tt>
Else If <span class="e2">D2</span>.<tt>WeakEqualityCompare</tt>(<span class="e2">E2</span>, <tt><b>E1</b></tt>): return <tt>true</tt>
return <tt>false</tt>
</pre>
</blockquote>
<h2 data-number="4.2" id="a-minimal-sketch-of-an-stderror-specification"><span class="header-section-number">4.2</span> A minimal sketch of an std::error specification<a href="#a-minimal-sketch-of-an-stderror-specification" class="self-link"></a></h2>
<p>The most significant types specified here are the <code class="sourceCode default">error</code> type itself, along with the <code class="sourceCode default">error_domain</code> abstract base type:</p>
<blockquote>
<pre>
<b>class</b> error_domain
{
<b>public</b>:
   <tt>constexpr</tt> error_domain_id id() <tt>const</tt> <b>noexcept</b>;

   <b>virtual</b> string_ref name() <tt>const</tt> <b>noexcept</b> = 0;
   <b>virtual</b> <tt>bool</tt> equivalent(<tt>const</tt> error&amp; lhs, <tt>const</tt> error&amp; rhs) <tt>const</tt> <b>noexcept</b> = 0;
   <b>virtual</b> string_ref message(<tt>const</tt> error&amp;) const <b>noexcept</b> = 0;
   <b>virtual</b> <tt>void</tt> throw_exception(<tt>const</tt> error&amp; e) <tt>const</tt>;

<b>protected</b>:
   <tt>constexpr</tt> <b>explicit</b> error_domain(error_domain_id id) <b>noexcept</b>;

   <tt>constexpr</tt> error_domain(error_domain_id id, error_resource_management erm) <b>noexcept</b>;

   error_domain(<tt>const</tt> error_domain&amp;) = <b>default</b>;
   error_domain(error_domain&amp;&amp;) = <b>default</b>;
   error_domain&amp; <b>operator</b> = (<tt>const</tt> error_domain&amp;) = <b>default</b>;
   error_domain&amp; <b>operator</b> = (error_domain&amp;&amp;) = <b>default</b>;
   ~error_domain() = <b>default</b>;
};

<tt>constexpr</tt> <tt>bool</tt> <b>operator</b> == (<tt>const</tt> error_domain&amp; lhs, <tt>const</tt> error_domain&amp; rhs) <b>noexcept</b>;
<tt>constexpr</tt> <tt>bool</tt> <b>operator</b> != (<tt>const</tt> error_domain&amp; lhs, <tt>const</tt> error_domain&amp; rhs) <b>noexcept</b>;

<span style="color:gray">// Exposition only</span>
<b>template</b> &lt;<b>class</b> T&gt;
<b>concept</b> TypeErasable = is_trivially_relocatable_v&lt;T&gt; &amp;&amp; (<b>sizeof</b>(T) &lt;= <b>sizeof</b>(std::<tt>intptr_t</tt>));

<b>class</b> error
{
<b>public</b>:
   <tt>constexpr</tt> error() <b>noexcept</b>;
   <tt>constexpr</tt> error(<tt>const</tt> error&amp; e);
   <tt>constexpr</tt> error(error&amp;&amp; e);

   <b>template</b> &lt;<b>class</b> T&gt; <b>requires</b> TypeErasable&lt;T&gt;
   <tt>constexpr</tt> error(<tt>const</tt> error_value&lt;T&gt;&amp; v, <tt>const</tt> error_domain&amp; d) <b>noexcept</b>(
      std::is_nothrow_copy_constructible_v&lt;T&gt; &amp;&amp; std::is_nothrow_move_constructible_v&lt;T&gt;
   );

   <b>template</b> &lt;<b>class</b> T&gt; <b>requires</b> TypeErasable&lt;T&gt;
   <tt>constexpr</tt> error(error_value&lt;T&gt;&amp;&amp; v, <tt>const</tt> error_domain&amp; d) <b>noexcept</b>(
      std::is_nothrow_move_constructible_v&lt;T&gt;
   );

   <tt>constexpr</tt> error(error_value&lt;&gt; v, <tt>const</tt> error_domain&amp; d) <b>noexcept</b>;

   <b>template</b> &lt;<b>class</b> A, <b>class</b>... Args&gt;
      <b>requires</b> <span style="color:gray">/* make_error((A&amp;&amp;)a, (Args&amp;&amp;)args...) via ADL returns an error object */</span>
   <tt>constexpr</tt> error(A&amp;&amp; a, Args&amp;&amp;... args) <b>noexcept</b>(<span style="color:gray">/* unspecified */</span>);

   error&amp; <b>operator</b> = (<tt>const</tt> error&amp; e);
   error&amp; <b>operator</b> = (error&amp;&amp; e) <b>noexcept</b>;
   ~error();

   <tt>const</tt> error_domain&amp; domain() <tt>const</tt> <b>noexcept</b>;

   string_ref message() <tt>const</tt> <b>noexcept</b>;

   <tt>[[noreturn]]</tt> <tt>void</tt> throw_exception() <tt>const</tt>;
};

bool <b>operator</b> == (<tt>const</tt> error&amp; lhs, <tt>const</tt> error&amp; rhs) <b>noexcept</b>;
bool <b>operator</b> != (<tt>const</tt> error&amp; lhs, <tt>const</tt> error&amp; rhs) <b>noexcept</b>;
</pre>
</blockquote>
<p>The class template <code class="sourceCode default">error_value</code> serves as a mechanism for constructing an <code class="sourceCode default">error</code> object from a TypeErasable object and an error_domain. In practice this class would likely only be used by <code class="sourceCode default">error_domain</code> implementors.</p>
<blockquote>
<pre>
<span style="color:gray">// Transports a type-erasable object of type T</span>
<b>template</b> &lt;<b>class</b> T = <tt>void</tt>&gt;
<b>class</b> error_value
{
<b>public:</b>
   <b>using</b> value_type = T;

   <tt>constexpr</tt> error_value(<tt>const</tt> T&amp; v) <b>noexcept</b>(
      std::is_nothrow_copy_constructible_v&lt;T&gt;
   );

   <tt>constexpr</tt> error_value(T&amp;&amp; v) <b>noexcept</b>(
      std::is_nothrow_move_constructible_v&lt;T&gt;
   );

   <tt>constexpr</tt> <tt>const</tt> T&amp; value() <tt>const</tt> &amp; <b>noexcept</b>;
   <tt>constexpr</tt> T&amp; value() &amp; noexcept;
   <tt>constexpr</tt> <tt>const</tt> T&amp;&amp; value() <tt>const</tt> &amp;&amp; <b>noexcept</b>;
   <tt>constexpr</tt> T&amp;&amp; value() &amp;&amp; <b>noexcept</b>;
};

<span style="color:gray">// Type-erasing specialization: type erases and transports a type-erased object</span>
<b>template</b> &lt;&gt;
<b>class</b> error_value&lt;<tt>void</tt>&gt;
{
<b>public</b>:
   <b>template</b> &lt;<b>class</b> T&gt; <b>requires</b> TypeErasable&lt;std::remove_cvref_t&lt;T&gt;&gt;
   <tt>constexpr</tt> error_value(T&amp;&amp; v) <b>noexcept</b>(<span style="color:gray">/* unspecified */</span>);

   <b>template</b> &lt;<b>class</b> T&gt; <b>requires</b> TypeErasable&lt;T&gt;
   <tt>constexpr</tt> error_value(<tt>const</tt> error_value&lt;T&gt;&amp; v) <b>noexcept</b>(<span style="color:gray">/* unspecified */</span>);

   <b>template</b> &lt;<b>class</b> T&gt; <b>requires</b> TypeErasable&lt;T&gt;
   <tt>constexpr</tt> error_value(error_value&lt;T&gt;&amp;&amp; v) <b>noexcept</b>(<span style="color:gray">/* unspecified */</span>)
};
</pre>
</blockquote>
<p>Additionally, an arbitrary type can be made implicitly convertible to an <code class="sourceCode default">error</code> via the <code class="sourceCode default">make_error</code> ADL-based customization point function.</p>
<p>The following free functions are provided for extracting the type-erased object from an <code class="sourceCode default">std::error</code> instance. This function is efficient but unsafe, as no type-checking is performed, so it should generally only be used directly by an <code class="sourceCode default">error_domain</code> object that has information about the erased type. These functions only participate in overload resolution if <code class="sourceCode default">T</code> is <code class="sourceCode default">TypeErasable</code>.</p>
<blockquote>
<pre>
<span style="color:gray">// Returns an instance of T that was directly copy-constructed from the internal error storage</span>
<b>template</b> &lt;<b>class</b> T&gt;
<tt>constexpr</tt> T error_cast(<tt>const</tt> error&amp; e) <b>noexcept</b>(<span style="color:gray">/* unspecified */</span>);

<span style="color:gray">// Returns an instance of T that was directly move-constructed from the internal error storage</span>
<b>template</b> &lt;<b>class</b> T&gt;
<tt>constexpr</tt> T error_cast(error&amp;&amp; e) <b>noexcept</b>(<span style="color:gray">/* unspecified */</span>);
</pre>
</blockquote>
<p>Finally, an <code class="sourceCode default">error_resource_management</code> class template is used to provide an <code class="sourceCode default">error_domain</code> with a copy-constructor, move-constructor, and destructor for a type-erased object.</p>
<blockquote>
<pre>
<b>struct</b> error_resource_management
{
   <b>using</b> copy_constructor = error_value&lt;<tt>void</tt>&gt;(*)(<tt>const</tt> error&amp;);
   <b>using</b> move_constructor = error_value&lt;<tt>void</tt>&gt;(*)(error&amp;&amp;);
   <b>using</b> destructor = <tt>void</tt>(*)(error&amp;);

   <tt>constexpr</tt> error_resource_management() <b>noexcept</b>;
   <tt>constexpr</tt> error_resource_management(copy_constructor, move_constructor, destructor) <b>noexcept</b>;
};
</pre>
</blockquote>
<p>For convenience, a <code class="sourceCode default">default error_resource_management</code> variable template is provided which automatically generates copy/move constructors and a destructor for an arbitrary <code class="sourceCode default">TypeErasable</code> type <code class="sourceCode default">T</code>:</p>
<blockquote>
<pre>
<b>template</b> &lt;<b>class</b> T&gt;
<tt>inline</tt> <tt>constexpr</tt> default_error_resource_management_t&lt;T&gt; default_error_resource_management {};
</pre>
</blockquote>
<p>The <code class="sourceCode default">default_error_resource_management_t</code> class must behave <em>as if</em> it was implemented as follows:</p>
<blockquote>
<pre>
<b>namespace</b> detail {

   <b>struct</b> default_error_constructors
   {
      <b>template</b> &lt;<b>class</b> T&gt;
      <b>static</b> error_value&lt;&gt; copy_constructor(<tt>const</tt> error&amp; e)
      {
         T value = error_cast&lt;T&gt;(e);
         <b>return</b> error_value&lt;&gt;{std::move(value)};
      }

      <b>template</b> &lt;<b>class</b> T&gt;
      <b>static</b> error_value&lt;&gt; move_constructor(error&amp;&amp; e)
      {
         <b>return</b> error_value&lt;&gt;{error_cast&lt;T&gt;(std::move(e))};
      }

      <b>template</b> &lt;<b>class</b> T&gt;
      <b>static</b> <tt>void</tt> destructor(error&amp; e) <b>noexcept</b>
      {
         <span style="color:gray"><i>unspecified_erased_error_ref</i></span> value = <span style="color:gray">/* unspecified: get reference to internal storage */</span>
         std::launder(<b>reinterpret_cast</b>&lt;T*&gt;(&amp;value.storage))-&gt;~T();
      }

      <b>template</b> &lt;<b>class</b> T&gt;
      <tt>constexpr</tt> <b>static</b> error_resource_management::copy_constructor copy() <b>noexcept</b>
      {
         <b>return</b> std::is_trivially_copy_constructible_v&lt;T&gt; ?
            <tt>nullptr</tt> : &amp;copy_constructor&lt;T&gt;;
      }

      <b>template</b> &lt;<b>class</b> T&gt;
      <tt>constexpr</tt> <b>static</b> error_resource_management::move_constructor move() <b>noexcept</b>
      {
         <b>return</b> std::is_trivially_move_constructible_v&lt;T&gt; ?
            <tt>nullptr</tt> : &amp;move_constructor&lt;T&gt;;
      }

      <b>template</b> &lt;<b>class</b> T&gt;
      <tt>constexpr</tt> <b>static</b> error_resource_management::destructor destroy() <b>noexcept</b>
      {
         <b>return</b> std::is_trivially_destructible_v&lt;T&gt; ?
            <tt>nullptr</tt> : &amp;destructor&lt;T&gt;;
      }
   };
}

<b>template</b> &lt;<b>class</b> T&gt;
<b>struct</b> default_error_resource_management_t : error_resource_management
{
   <tt>constexpr</tt> default_error_resource_management_t() <b>noexcept</b>
      : 
      error_resource_management{
         detail::default_error_constructors::copy&lt;T&gt;(),
         detail::default_error_constructors::move&lt;T&gt;(),
         detail::default_error_constructors::destroy&lt;T&gt;()
      }
   {}
};
</pre>
</blockquote>
<p>As with the <code class="sourceCode default">status_code</code>-based implementation proposed in <span class="citation" data-cites="P1028">[<a href="#ref-P1028" role="doc-biblioref">P1028R3</a>]</span>, a <code class="sourceCode default">string_ref</code> type along with a reference-counted shared-ownership version (here called <code class="sourceCode default">shared_string_ref</code>) is provided for storing and transporting error messages.</p>
<p>The submitted implementation defines the following <code class="sourceCode default">error_domain</code>s:</p>
<blockquote>
<ol type="1">
<li><p><strong>generic_domain</strong>: transports an <code class="sourceCode default">std::errc</code>, supports weak-equality comparison with <code class="sourceCode default">std::errc</code>, <code class="sourceCode default">dynamic_exception_errc</code>, <code class="sourceCode default">std::error_code</code> or an <code class="sourceCode default">error</code> object transporting any of these or an <code class="sourceCode default">error</code> object transporting an <code class="sourceCode default">std::exception_ptr</code>.</p></li>
<li><p><strong>error_code_domain</strong>: transports an <code class="sourceCode default">std::error_code</code>, supports weak-equality comparison to <code class="sourceCode default">std::error_code</code>, <code class="sourceCode default">std::errc</code>, or an <code class="sourceCode default">error</code> object transporting any of these or an error object transporting an <code class="sourceCode default">std::exception_ptr</code></p></li>
<li><p><strong>dynamic_exception_domain</strong>: stores an <code class="sourceCode default">std::exception_ptr</code>, supports weak-equality comparison with <code class="sourceCode default">dynamic_exception_errc</code>, <code class="sourceCode default">std::errc</code>, <code class="sourceCode default">std::error_code</code>, or an <code class="sourceCode default">error</code> object transporting any of these or an <code class="sourceCode default">error</code> object transporting an <code class="sourceCode default">std::exception_ptr</code>.</p></li>
<li><p><strong>dynamic_exception_code_domain</strong>: stores a <code class="sourceCode default">dynamic_exception_errc</code>, supports weak-equality comparison with <code class="sourceCode default">dynamic_exception_errc</code>, <code class="sourceCode default">std::errc</code>, <code class="sourceCode default">std::error_code</code> or an <code class="sourceCode default">error</code> object transporting any of these or an error object transporting an <code class="sourceCode default">std::exception_ptr</code>.</p></li>
</ol>
</blockquote>
<p>Per the above discussion of POSIX error codes as insuitable for a generic error domain, I would alternatively propose that <code class="sourceCode default">generic_domain</code> be changed to <code class="sourceCode default">posix_domain</code>, and <code class="sourceCode default">dynamic_exception_code_domain</code> be reworked into an error_domain for generic application-level error codes, including individual codes for each standard C++ exception type. Additionally, I would propose including <code class="sourceCode default">system_domain</code> which, similarly to the current <code class="sourceCode default">std::system_category</code>, transports error codes returned from an Operating System API and provides semantic comparison to the portable set of POSIX errors defined in <code class="sourceCode default">std::errc</code>.</p>
<h1 data-number="5" id="bibliography"><span class="header-section-number">5</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references hanging-indent" role="doc-bibliography">
<div id="ref-libstdcpp">
<p>[GNU libstdc++] GNU libstdc++ implements a single-pointer-sized exception_ptr. <br />
<a href="https://godbolt.org/z/wBVejv">https://godbolt.org/z/wBVejv</a></p>
</div>
<div id="ref-N2351">
<p>[N2351] Peter Dimov and Beman Dawes. 2007. Improving shared_ptr for C++0x, Revision 2. <br />
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2351.htm#aliasing">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2351.htm#aliasing</a></p>
</div>
<div id="ref-P0709">
<p>[P0709R4] Herb Sutter. 2019. Zero-overhead deterministic exceptions. <br />
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0709r4.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0709r4.pdf</a></p>
</div>
<div id="ref-P1028">
<p>[P1028R3] Niall Douglas. 2020. SG14 status_code and standard error object. <br />
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1028r3.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1028r3.pdf</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
