<!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" />
  <title>An Allocator-Aware `inplace_vector`</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: left;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
div.wrapper {
max-width: 60em;
margin: auto;
}

ul {
list-style-type: none;
padding-left: 2.5em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
ol {
padding-left: 2.5em;
}
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;
}

#TOC ul > li:before {
content: none;
}
#TOC > ul {
padding-left: 0;
}

.toc-section-number {
margin-right: 0.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: left; }
div.section { text-align: left; }
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">An Allocator-Aware
<code class="sourceCode default">inplace_vector</code></h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3160R1</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td><!-- $TimeStamp$ -->
2024-03-08 20:42 EST<!-- $ --></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>
      LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Pablo Halpern<br>&lt;<a href="mailto:phalpern@halpernwightsoftware.com" class="email">phalpern@halpernwightsoftware.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" id="toc-abstract"><span class="toc-section-number">1</span> Abstract<span></span></a></li>
<li><a href="#change-log" id="toc-change-log"><span class="toc-section-number">2</span> Change Log<span></span></a></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">3</span> Motivation<span></span></a>
<ul>
<li><a href="#general-motivation-for-allocator-aware-types" id="toc-general-motivation-for-allocator-aware-types"><span class="toc-section-number">3.1</span> General Motivation for
Allocator-Aware Types<span></span></a></li>
<li><a href="#motivation-for-an-allocator-aware-inplace_vector" id="toc-motivation-for-an-allocator-aware-inplace_vector"><span class="toc-section-number">3.2</span> Motivation for an Allocator-Aware
<code class="sourceCode default">inplace_vector</code><span></span></a></li>
</ul></li>
<li><a href="#proposal-summary" id="toc-proposal-summary"><span class="toc-section-number">4</span> Proposal Summary<span></span></a>
<ul>
<li><a href="#design-decision-for-discussion" id="toc-design-decision-for-discussion"><span class="toc-section-number">4.1</span> Design Decision for
Discussion<span></span></a></li>
</ul></li>
<li><a href="#alternatives-considered" id="toc-alternatives-considered"><span class="toc-section-number">5</span> Alternatives
Considered<span></span></a>
<ul>
<li><a href="#option-1-inplace_vectorclass-t-size_t-n-class-alloc-stdallocatort" id="toc-option-1-inplace_vectorclass-t-size_t-n-class-alloc-stdallocatort"><span class="toc-section-number">5.1</span> Option 1: <code class="sourceCode default">inplace_vector&lt;class T, size_t N, class Alloc = std::allocator&lt;T&gt;&gt;</code><span></span></a></li>
<li><a href="#option-2-inplace_vectorclass-t-size_t-n" id="toc-option-2-inplace_vectorclass-t-size_t-n"><span class="toc-section-number">5.2</span> Option 2: <code class="sourceCode default">inplace_vector&lt;class T, size_t N&gt;</code><span></span></a></li>
<li><a href="#option-3-inplace_vectorclass-t-size_t-n-class-alloc-see-below" id="toc-option-3-inplace_vectorclass-t-size_t-n-class-alloc-see-below"><span class="toc-section-number">5.3</span> Option 3: <code class="sourceCode default">inplace_vector&lt;class T, size_t N, class Alloc =</code>
<em>see below</em>
<code class="sourceCode default">&gt;</code><span></span></a></li>
<li><a href="#option-4-basic_inplace_vectorclass-t-size_t-n-class-alloc" id="toc-option-4-basic_inplace_vectorclass-t-size_t-n-class-alloc"><span class="toc-section-number">5.4</span> Option 4: <code class="sourceCode default">basic_inplace_vector&lt;class T, size_t N, class Alloc&gt;</code><span></span></a></li>
</ul></li>
<li><a href="#performance-and-compile-time-costs" id="toc-performance-and-compile-time-costs"><span class="toc-section-number">6</span> Performance and Compile-Time
Costs<span></span></a>
<ul>
<li><a href="#about-the-performance-tests" id="toc-about-the-performance-tests"><span class="toc-section-number">6.1</span> About the Performance
Tests<span></span></a></li>
<li><a href="#methodology" id="toc-methodology"><span class="toc-section-number">6.2</span> Methodology<span></span></a></li>
<li><a href="#runtime-results" id="toc-runtime-results"><span class="toc-section-number">6.3</span> Runtime
Results<span></span></a></li>
<li><a href="#compile-time-results" id="toc-compile-time-results"><span class="toc-section-number">6.4</span> Compile-Time
Results<span></span></a></li>
</ul></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">7</span> Wording<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">8</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>The <code class="sourceCode default">inplace_vector</code> proposal,
<span class="citation" data-cites="P0843R10">[<a href="#ref-P0843R10" role="doc-biblioref">P0843R10</a>]</span>, is moving forward without
allocator support. This paper proposes that
<code class="sourceCode default">inplace_vector</code> <em>should</em>
have allocator support and explores the pros and cons of adding such
support directly into
<code class="sourceCode default">inplace_vector</code> vs. into a
separate <code class="sourceCode default">basic_inplace_vector</code>
class template. This proposal is distinct from <span class="citation" data-cites="P0843R10">[<a href="#ref-P0843R10" role="doc-biblioref">P0843R10</a>]</span> so that the latter can move
forward quickly while allocator-specific policies are still being
resolved.</p>
<h1 data-number="2" id="change-log"><span class="header-section-number">2</span> Change Log<a href="#change-log" class="self-link"></a></h1>
<p><strong>R1</strong></p>
<ul>
<li><a href="#proposal-summary">Proposal Summary</a> section added</li>
<li><em>Design Options</em> section renamed to <a href="#alternatives-considered">Alternatives Considered</a></li>
<li><em>Compile-Time Data</em> section significantly expanded and
renamed to <a href="#performance-and-compile-time-costs">Performance and
Compile-Time Costs</a></li>
<li>Miscellaneous copy editing</li>
</ul>
<p><strong>R0</strong></p>
<ul>
<li>Initial version</li>
</ul>
<h1 data-number="3" id="motivation"><span class="header-section-number">3</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<h2 data-number="3.1" id="general-motivation-for-allocator-aware-types"><span class="header-section-number">3.1</span> General Motivation for
Allocator-Aware Types<a href="#general-motivation-for-allocator-aware-types" class="self-link"></a></h2>
<p><em>Note: The text below is borrowed nearly verbatim from <span class="citation" data-cites="P3002R1">[<a href="#ref-P3002R1" role="doc-biblioref">P3002R1</a>]</span>, which proposes a general
policy for when types should use allocators.</em></p>
<p>Memory management is a major part of building software. Numerous
facilities in the C++ Standard library exist to give the programmer
maximum control over how their program uses memory.</p>
<ul>
<li><p><code class="sourceCode default">std::unique_ptr</code> and
<code class="sourceCode default">std::shared_ptr</code> are
parameterized with <em>deleter</em> objects that control, among other
things, how memory resources are reclaimed.</p></li>
<li><p><code class="sourceCode default">std::vector</code> is preferred
over other containers in many cases because its use of contiguous memory
provides optimal cache locality and minimizes allocate and deallocate
operations. Indeed, the LEWG has spent a lot of time on
<code class="sourceCode default">flat_set</code> (<span class="citation" data-cites="P1222R0">[<a href="#ref-P1222R0" role="doc-biblioref">P1222R0</a>]</span>) and
<code class="sourceCode default">flat_map</code> (<span class="citation" data-cites="P0429R3">[<a href="#ref-P0429R3" role="doc-biblioref">P0429R3</a>]</span>), whose underlying structure
defaults, for this reason, to
<code class="sourceCode default">vector</code>.</p></li>
<li><p>Operators <code class="sourceCode default">new</code> and
<code class="sourceCode default">delete</code> are replaceable, giving
programmers global control over how memory is allocated.</p></li>
<li><p>The C++ object model makes a clear distinction between an
object’s memory footprint and its lifetime.</p></li>
<li><p>Language constructs such as
<code class="sourceCode default">void*</code> and
<code class="sourceCode default">reinterpet_cast</code> provide
fine-grained access to objects’ underlying memory.</p></li>
<li><p>Standard containers and strings are parameterized with
allocators, providing object-level control over memory allocation and
element construction.</p></li>
</ul>
<p>This fine-grained control over memory that C++ gives the programmer
is a large part of why C++ is applicable to so many domains — from
embedded systems with limited memory budgets to games, high-frequency
trading, and scientific simulations that require cache locality, thread
affinity, and other memory-related performance optimizations.</p>
<p>An in-depth description of the value proposition for allocator-aware
software can be found in <span class="citation" data-cites="P2035R0">[<a href="#ref-P2035R0" role="doc-biblioref">P2035R0</a>]</span>. Standard
containers are the most ubiquitous examples of <em>allocator-aware</em>
types. Their <code class="sourceCode default">allocator_type</code> and
<code class="sourceCode default">get_allocator</code> members and
allocator-parameterized constructors allow them to be used like building
blocks that can be combined and nested as necessary while retaining full
programmer control over how the whole assembly allocates memory. For
<em>scoped allocators</em> (i.e., those that apply not only to the
top-level container, but also to its elements), having each element of a
container support a predictable allocator-aware interface is crucial to
giving the programmer the ability to allocate all memory from a single
memory resource, such as an arena or pool. Note that the allocator is a
<em>configuration</em> parameter of an object and does not contribute to
its value.</p>
<p>In short, four principles underlie this policy proposal.</p>
<ol type="1">
<li><p><strong>The Standard Library should be general and
flexible</strong>. The user of a library class should have control, to
the greatest extent possible, over how memory is allocated.</p></li>
<li><p><strong>The Standard Library should be consistent</strong>. The
use of allocators should be consistent with the existing allocator-aware
classes and class templates, especially those in the containers
library.</p></li>
<li><p><strong>The parts of the Standard Library should work
together</strong>. If one part of the library gives the user control
over memory allocation but another part does not, then the second part
undermines the utility of the first.</p></li>
<li><p><strong>The Standard Library should encapsulate
complexity</strong>. The generic application of allocators with maximum
flexibility is potentially complex and is best left to the experts
implementing the Standard Library. Users can choose their own subset of
desirable allocator behavior only if the underlying Library classes
allow them to choose their preferred approach, whether it be stateless
allocators, statically typed allocators, polymorphic allocators, or no
allocators.</p></li>
</ol>
<h2 data-number="3.2" id="motivation-for-an-allocator-aware-inplace_vector"><span class="header-section-number">3.2</span> Motivation for an
Allocator-Aware <code class="sourceCode default">inplace_vector</code><a href="#motivation-for-an-allocator-aware-inplace_vector" class="self-link"></a></h2>
<p>The main motivations for
<code class="sourceCode default">inplace_vector</code> as a whole are to
give the user control over memory allocation. If such a type did not fit
into an existing infrastructure that is also designed to give the user
control over memory use, that would certainly seem ironic.</p>
<p>Although the objects stored in an
<code class="sourceCode default">std::inplace_vector</code>, as proposed
in <span class="citation" data-cites="P0843R10">[<a href="#ref-P0843R10" role="doc-biblioref">P0843R10</a>]</span>, can be emplaced with any set
of valid constructor arguments, including allocator arguments, the fact
that the <code class="sourceCode default">inplace_vector</code> itself
is not allocator aware prevents it from working consistently with other
parts of the Standard Library, specifically those parts that depend on
<em>uses-allocator construction</em> (section
[allocator.uses.construction]) in the Standard:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>pmr::monotonic_buffer_resource rsrc;</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>pmr::polymorphic_allocator&lt;&gt; alloc{ &amp;rsrc };</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>using V = inplace_vector&lt;pmr::string, 10&gt;;</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>V v = make_obj_using_allocator&lt;V&gt;(alloc, { &quot;hello&quot;, &quot;goodbye&quot; });</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>assert(v[0].get_allocator() == alloc);  // FAILS</span></code></pre></div>
<p>Even though an allocator is supplied, it is not used to construct the
<code class="sourceCode default">pmr::string</code> objects within the
resulting <code class="sourceCode default">inplace_vector</code> object
because <code class="sourceCode default">inplace_vector</code> does not
have the necessary hooks for
<code class="sourceCode default">make_obj_using_allocator</code> to
recognize it as being allocator aware. Note that, although this example
and the ones that follow use
<code class="sourceCode default">pmr::polymorphic_allocator</code>, the
same issues would apply to any scoped allocator.</p>
<p><em>Uses-allocator construction</em> is rarely used directly in user
code. Instead, it is used within the implementation of standard
containers and scoped allocators to ensure that the allocator used to
construct the container is also used to construct its elements.
Continuing the example above, consider what happens if an
<code class="sourceCode default">inplace_vector</code> is stored in a
<code class="sourceCode default">pmr::vector</code> compared to truly
allocator-aware type
(<code class="sourceCode default">pmr::string</code>) in a
<code class="sourceCode default">pmr::vector</code>:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>pmr::vector&lt;pmr::string&gt; vs(alloc);</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>pmr::vector&lt;V&gt;           vo(alloc);</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>vs.emplace_back(&quot;hello&quot;);</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>vo.emplace_back({ &quot;hello&quot; });</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>assert(vs.back().get_allocator() == alloc);      // OK</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>assert(vo.back()[0]-&gt;get_allocator() == alloc);  // FAILS</span></code></pre></div>
<p>An important invariant when using a scoped allocator such as
<code class="sourceCode default">pmr::polymorphic_allocator</code> is
that the same allocator is used throughout an object hierarchy.
<code class="sourceCode default">inplace_vector</code> cannot ensure
that this invariant is preserved, even if each element is originally
inserted with the correct allocator, because
<code class="sourceCode default">inplace_vector</code> does not remember
the allocator used to construct it and thus cannot supply the allocator
to new elements. The abstraction has become unreliable and the
programmer must manually enforce the scoped-allocator invariant.</p>
<h1 data-number="4" id="proposal-summary"><span class="header-section-number">4</span> Proposal Summary<a href="#proposal-summary" class="self-link"></a></h1>
<p>The proposal offered here is to make
<code class="sourceCode default">inplace_vector</code> an
<em>allocator-aware container</em> as described in <span>24.2.2.5
<a href="https://wg21.link/N4971#container.alloc.reqmts">[container.alloc.reqmts]</a><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></span> and as specified below.</p>
<ul>
<li>The class template would have a third template argument,
<code class="sourceCode default">Allocator</code>, which would default
to <code class="sourceCode default">std::allocator&lt;T&gt;</code>. The
<code class="sourceCode default">std::pmr</code> namespace would also
contain an alias:</li>
</ul>
<blockquote>
<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="dt">size_t</span> N, <span class="kw">class</span> Allocator <span class="op">=</span> allocator<span class="op">&lt;</span>T<span class="op">&gt;&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> inplace_vector; <span class="co">// partially freestanding</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> pmr</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T, <span class="dt">size_t</span> N<span class="op">&gt;</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> inplace_vector <span class="op">=</span> std<span class="op">::</span>inplace_vector<span class="op">&lt;</span>T, N, polymorphic_allocator<span class="op">&lt;</span>T<span class="op">&gt;&gt;</span>;</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<ul>
<li>The interface would add
<code class="sourceCode default">allocator_type</code> and
<code class="sourceCode default">get_allocator</code> members:</li>
</ul>
<blockquote>
<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">using</span> allocator_type <span class="op">=</span> Allocator;</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> allocator_type get_allocator<span class="op">()</span> <span class="kw">const</span>;</span></code></pre></div>
</blockquote>
<ul>
<li>Every constructor would have either an overload or a default
argument allowing the allocator to be passed as its last argument:</li>
</ul>
<blockquote>
<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">constexpr</span> inplace_vector<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span> inplace_vector<span class="op">(</span><span class="kw">const</span> allocator_type<span class="op">&amp;</span> a<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span> inplace_vector<span class="op">(</span>size_type n<span class="op">)</span>; <span class="co">// freestanding-deleted</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> inplace_vector<span class="op">(</span>size_type n,</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>                         <span class="kw">const</span> allocator_type<span class="op">&amp;</span> a<span class="op">)</span>; <span class="co">// freestanding-deleted</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> inplace_vector<span class="op">(</span>size_type n, <span class="kw">const</span> T<span class="op">&amp;</span> value,</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>                         <span class="kw">const</span> allocator_type<span class="op">&amp;</span> a <span class="op">=</span> <span class="op">{})</span>; <span class="co">// freestanding-deleted</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="co">// etc..</span></span></code></pre></div>
</blockquote>
<ul>
<li>If the element type, <code class="sourceCode default">T</code>, uses
the specified allocator (i.e., <code class="sourceCode default">uses_allocator_v&lt;T, Allocator&gt;</code>
is <code class="sourceCode default">true</code>), then the allocator is
passed to the constructor of <code class="sourceCode default">T</code>
via <em>uses-allocator construction</em> (<span>20.2.8.2
<a href="https://wg21.link/N4971#allocator.uses.construction">[allocator.uses.construction]</a></span>)
when elements are inserted into the
<code class="sourceCode default">inplace_vector</code>.</li>
</ul>
<h2 data-number="4.1" id="design-decision-for-discussion"><span class="header-section-number">4.1</span> Design Decision for
Discussion<a href="#design-decision-for-discussion" class="self-link"></a></h2>
<p>For wrapper types such as
<code class="sourceCode default">tuple&lt;T&gt;</code>, an allocator
passed to the constructor is passed through to the wrapped
<code class="sourceCode default">T</code> object via <em>uses-allocator
construction</em> (<span>20.2.8.2
<a href="https://wg21.link/N4971#allocator.uses.construction">[allocator.uses.construction]</a></span>),
regardless of whether the allocator is a scoped allocator. The reasoning
is that, since the <code class="sourceCode default">tuple</code> does
not itself allocate memory, passing in an allocator that is compatible
with <code class="sourceCode default">T</code> but which is not passed
to the wrapped <code class="sourceCode default">T</code> object makes no
sense. The same logic applies to the proposed
<code class="sourceCode default">basic_optional</code> and
<code class="sourceCode default">basic_variant</code> templates proposed
in <span class="citation" data-cites="P2047R7">[<a href="#ref-P2047R7" role="doc-biblioref">P2047R7</a>]</span> and <span class="citation" data-cites="P3153R0">[<a href="#ref-P3153R0" role="doc-biblioref">P3153R0</a>]</span>, respectively.</p>
<p>On the other hand, the requirements on an allocator-aware container
in <span>24.2.2.5
<a href="https://wg21.link/N4971#container.alloc.reqmts">[container.alloc.reqmts]</a></span>
indicate that elements should always be constructed using <code class="sourceCode default">allocator_traits&lt;Allocator&gt;::construct</code>.
A nonintuitive downside of following this convention is that only an
allocator having a special
<code class="sourceCode default">construct</code> method, such as a
scoped allocator, would be used to construct elements; other allocator
types would effectively be ignored (but they might take up space in the
object footprint). The main upside, however, is that the existing
wording in <span>20.2.8.2
<a href="https://wg21.link/N4971#allocator.uses.construction">[allocator.uses.construction]</a></span>
would apply unchanged, including the definitions of
<em>Cpp17DefaultInsertable</em>, <em>Cpp17MoveInsertable</em>,
<em>Cpp17CopyInsertable</em>, <em>Cpp17EmplaceConstructible</em>, and
<em>Cpp17Erasable</em>.</p>
<p>To summarize:</p>
<ul>
<li><p><em>Uses-allocator construction</em> is consistent with other
nonallocating types that contain allocating types.</p></li>
<li><p><code class="sourceCode default">allocator_traits&lt;Allocator&gt;::construct</code>
is consistent with other containers, including
<code class="sourceCode default">std::vector</code>.</p></li>
<li><p>For most scoped allocators, including
<code class="sourceCode default">pmr::polymorphic_allocator</code>, the
two designs are equivalent. If a scoped allocator uses different
allocation mechanisms at different nesting levels, however,
<code class="sourceCode default">construct</code> will use the top level
mechanism to construct objects, but not to allocate memory.</p></li>
<li><p>Workarounds employing the
<code class="sourceCode default">scoped_allocator_adaptor</code> would
let each design behave like the other.</p></li>
</ul>
<p>The design in this document constructs elements via
<em>uses-allocator construction</em>, but LEWG should consider this
issue carefully, including in the context of a larger policy
discussion.</p>
<h1 data-number="5" id="alternatives-considered"><span class="header-section-number">5</span> Alternatives Considered<a href="#alternatives-considered" class="self-link"></a></h1>
<p>Several possible designs for an allocator-aware
<code class="sourceCode default">inplace_vector</code> have been
considered. Option 1 — with none of its suboptions — is being proposed
here.</p>
<h2 data-number="5.1" id="option-1-inplace_vectorclass-t-size_t-n-class-alloc-stdallocatort"><span class="header-section-number">5.1</span> Option 1: <code class="sourceCode default">inplace_vector&lt;class T, size_t N, class Alloc = std::allocator&lt;T&gt;&gt;</code><a href="#option-1-inplace_vectorclass-t-size_t-n-class-alloc-stdallocatort" class="self-link"></a></h2>
<p>The allocator would be stored in the object and returned by
<code class="sourceCode default">get_allocator()</code>. If
<code class="sourceCode default">uses_allocator_v&lt;T, Alloc&gt;</code>
is true, then elements are constructed via <em>uses-allocator
construction</em> with the supplied allocator. For
<code class="sourceCode default">std::allocator</code>, no space would
be need to be taken up; in fact, consuming no space should be a
<em>requirement</em> so that <code class="sourceCode default">sizeof(inplace_vector&lt;T, N&gt;)</code> is
guaranteed to be <em>N</em> *
<code class="sourceCode default">sizeof(T)</code>, i.e., no size
overhead for the default allocator case.</p>
<p><strong>Pros</strong>: This option offers the simplest design, is
most consistent with other containers, and has zero runtime overhead for
the default case.</p>
<p><strong>Cons</strong>: If
<code class="sourceCode default">uses_allocator_v&lt;T, Alloc&gt;</code>
is false and <code class="sourceCode default">Alloc</code> is a nonempty
class, then space is wasted storing an unused allocator.</p>
<p><strong>Suboptions for reducing wasted footprint storage</strong> for
non-AA elements:</p>
<ol type="a">
<li><p>In this case,
<code class="sourceCode default">inplace_vector</code> could be
non-allocator-aware,
<code class="sourceCode default">allocator_type</code> and
<code class="sourceCode default">get_allocator()</code> would not be
defined, and no constructors would accept an allocator
argument.</p></li>
<li><p>Supplying an allocator other than
<code class="sourceCode default">std::allocator</code> for a type that
cannot use it could be ill-formed.</p></li>
</ol>
<p>Unfortunately, both sub-options would make generic programming
somewhat more difficult.</p>
<h2 data-number="5.2" id="option-2-inplace_vectorclass-t-size_t-n"><span class="header-section-number">5.2</span> Option 2: <code class="sourceCode default">inplace_vector&lt;class T, size_t N&gt;</code><a href="#option-2-inplace_vectorclass-t-size_t-n" class="self-link"></a></h2>
<p>If <code class="sourceCode default">T::allocator_type</code> exists,
then <code class="sourceCode default">inplace_vector&lt;class T, size_t N&gt;::allocator_type</code>
would also exist, as would
<code class="sourceCode default">get_allocator()</code> and
allocator-accepting constructors. Otherwise, the instantiation would not
be allocator aware.</p>
<p><strong>Pros</strong>: The user cannot accidentally forget to specify
an allocator parameter when using allocator-aware element types.</p>
<p><strong>Cons</strong>: If <code class="sourceCode default">T</code>
is allocator aware but the user doesn’t want to take advantage of that
quality, an allocator is stored unnecessarily. Worse, no obvious
workarounds are available to avoid storing and using an allocator. This
approach is inconsistent with other containers; nowhere else in the
Standard does a container-element’s allocator type influence the
allocator type of the container itself.</p>
<h2 data-number="5.3" id="option-3-inplace_vectorclass-t-size_t-n-class-alloc-see-below"><span class="header-section-number">5.3</span> Option 3: <code class="sourceCode default">inplace_vector&lt;class T, size_t N, class Alloc =</code>
<em>see below</em> <code class="sourceCode default">&gt;</code><a href="#option-3-inplace_vectorclass-t-size_t-n-class-alloc-see-below" class="self-link"></a></h2>
<p>The <em>see below</em> type is
<code class="sourceCode default">T::allocator_type</code> if such a type
exists and
<code class="sourceCode default">std::allocator&lt;byte&gt;</code>
otherwise.</p>
<p><strong>Pros</strong>: Accidentally forgetting to specify an
allocator parameter when using allocator-aware types is easily avoided
(as in Option 2), but automatic allocator selection can be easily
overridden.</p>
<p><strong>Cons</strong>: Automatically detecting the element’s
allocator type is novel and inconsistent with other containers. When an
allocator is not supplied by the user, the resulting
<code class="sourceCode default">inplace_vector</code> might be
unintentionally allocator aware, incurring performance penalties. Such
accidents are the flip side of the Pros for this option; some accidents
are avoided while different accidents can now occur.</p>
<h2 data-number="5.4" id="option-4-basic_inplace_vectorclass-t-size_t-n-class-alloc"><span class="header-section-number">5.4</span> Option 4: <code class="sourceCode default">basic_inplace_vector&lt;class T, size_t N, class Alloc&gt;</code><a href="#option-4-basic_inplace_vectorclass-t-size_t-n-class-alloc" class="self-link"></a></h2>
<p>This approach has a separate template,
<code class="sourceCode default">basic_inplace_vector</code>, that is
the same as the allocator-aware
<code class="sourceCode default">inplace_vector</code> proposed in
Options 1 or 3, but without affecting the interface of
<code class="sourceCode default">inplace_vector</code> proposed in <span class="citation" data-cites="P0843R10">[<a href="#ref-P0843R10" role="doc-biblioref">P0843R10</a>]</span>.</p>
<p><strong>Pros</strong>: This option reduces complications in the
<code class="sourceCode default">inplace_vector</code> specification and
implementation and potentially reduces compile time compared to some of
the preceding options.</p>
<p><strong>Cons</strong>:
<code class="sourceCode default">inplace_vector</code> and
<code class="sourceCode default">basic_inplace_vector</code> are
separate, incompatible, types. The user needs to make a decision,
especially in generic code, regarding whether they ever expect to have
allocator-aware elements. Choosing the shorter name is tempting, but
comes at the expense of breaking scoped allocation in generic code. This
option increases <em>overall</em> specification complexity and
implementation because now <em>two</em> classes must be specified,
implemented, and tested, so
<code class="sourceCode default">basic_inplace_vector</code> is just as
complicated as Options 1 or 3, above.</p>
<h1 data-number="6" id="performance-and-compile-time-costs"><span class="header-section-number">6</span> Performance and Compile-Time
Costs<a href="#performance-and-compile-time-costs" class="self-link"></a></h1>
<h2 data-number="6.1" id="about-the-performance-tests"><span class="header-section-number">6.1</span> About the Performance Tests<a href="#about-the-performance-tests" class="self-link"></a></h2>
<p>When people talk about “low- or no-cost abstractions,” they usually
mean runtime costs, but we are increasingly seeing concern about
compile-time costs, as metaprogramming and concepts allow us to express
ever-more complex constructs. Collecting data on both the runtime and
compile-time costs of adding generic allocator awareness to
<code class="sourceCode default">inplace_vector</code> is, therefore,
important to aid the Committee in evaluating the options.</p>
<p>I performed a set of experiments with a subset of an
<code class="sourceCode default">inplace_vector</code> implementation,
looking at the generated assembly code and measuring compile times for a
non-allocator-aware version, as proposed in <span class="citation" data-cites="P0843R10">[<a href="#ref-P0843R10" role="doc-biblioref">P0843R10</a>]</span>, compared to Options 1, 2, and
3 described above. Option 4 was not measured since it involves a
completely separate class template,
<code class="sourceCode default">basic_inplace_vector</code>, that
presumably would not affect the performance of the unmodified
<code class="sourceCode default">inplace_vector</code> except for the
nominal cost of reading the text of the header file at compilation
time.</p>
<p>The <a href="#runtime-results">runtime</a> and <a href="#compile-time-results">compile-time results</a> are shown below,
after the <a href="#methodology">Methodology</a> section.</p>
<h2 data-number="6.2" id="methodology"><span class="header-section-number">6.2</span> Methodology<a href="#methodology" class="self-link"></a></h2>
<p>Allocator awareness was added to a partial implementation of <span class="citation" data-cites="P0843R10">[<a href="#ref-P0843R10" role="doc-biblioref">P0843R10</a>]</span>. To save effort, only
functionality needed for the test program was implemented. For the
allocator-aware versions of
<code class="sourceCode default">inplace_vector</code>, compile time was
reduced marginally by implementing a partial specialization for the
common case of <code class="sourceCode default">std::allocator</code>.
The test driver was designed to maximize the number of distinct
instantiations of
<code class="sourceCode default">inplace_vector</code>, its
constructors, and its insertion methods (especially
<code class="sourceCode default">push_back</code>), thus producing a
near-worst-case scenario for any template-instantiation penalty caused
by the inclusion of the allocator machinery.</p>
<p>Compilation was launched from a Python script that compiled but did
not link five identical files, each of which
<code class="sourceCode default">#include</code>d the test program.
Compilation was timed for each combination of implementation option,
compiler, and element types (allocator-ware, non-allocator-aware or
blended/both). The script also generated one assembly listing and one
executable for each configuration. The generation of the assembly and
executable files was not included in the timing tests. The executable
was run as a <em>smoke test</em> to ensure that the code ran and passed
some simple tests, but the run time was too short for any meaningful
comparisons and so was not measured; runtime performance equivalence was
deduced based on assembly-language equivalence. Timing jitter was on the
order of 3-4%, so timing differences under 5% should be ignored.</p>
<p>The tests were run on a Lenovo ThinkPad running Ubuntu 22.04 Linux
within the Windows Subsystem for Linux. The CPU was an 11th Gen Intel(R)
Core(TM) i7-11850H running at 2.50GH with 64GB RAM and a 512GB SSD. The
compilers used in the test were GCC 11.4.0 using
<code class="sourceCode default">-std=C++23</code> and Clang 14.0.0
using <code class="sourceCode default">-std=C++2b</code>. All tests were
conducted with level <code class="sourceCode default">-O2</code>
optimization. The experimental sources and scripts can be found at <a href="https://github.com/phalpern/WG21-halpern/tree/main/P3160-AA-inplace_vector/">https://github.com/phalpern/WG21-halpern/tree/main/P3160-AA-inplace_vector/</a>.</p>
<h2 data-number="6.3" id="runtime-results"><span class="header-section-number">6.3</span> Runtime Results<a href="#runtime-results" class="self-link"></a></h2>
<p>The test program was not designed to measure run time. Although a
smoke test was performed on each option to test that it produced correct
results, run times were too short to produce meaningful comparisons.
Instead, I compared assembly-language output from each configuration to
see if the presence of the allocator machinery produced any difference
in the generated output for both allocator-aware element types and
non-allocator-aware element types. Comparing GCC-to-GCC and
Clang-to-Clang produced the same results, shown in the table below.</p>
<p><em>Comparing assembly-language output against P0843R10</em></p>
<table>
<thead>
<tr class="header">
<th></th>
<th><div style="text-align:center">
<strong>Non-allocator-aware
<code class="sourceCode default">T</code></strong>
</div></th>
<th><div style="text-align:center">
<strong>Allocator-aware
<code class="sourceCode default">T</code></strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Option 1</td>
<td><strong>Identical</strong></td>
<td><strong>Identical</strong></td>
</tr>
<tr class="even">
<td>Option 2</td>
<td><strong>Identical</strong></td>
<td><em>Different</em></td>
</tr>
<tr class="odd">
<td>Option 3</td>
<td><strong>Identical</strong></td>
<td><em>Different</em></td>
</tr>
</tbody>
</table>
<p>From this table, we can infer that the allocator machinery incurs no
runtime penalty when the element type does not use an allocator.
Moreover, Option 1 produced no penalty when the element types
<em>do</em> use an allocator, provided that the allocator was not
specifically provided to
<code class="sourceCode default">inplace_vector</code>, i.e., when
<code class="sourceCode default">inplace_vector</code> was instantiated
with the default allocator
(<code class="sourceCode default">std::allocator&lt;T&gt;</code>).
Options 2 and 3 produced different results for allocator-aware element
types, as expected, since the default allocator type for
<code class="sourceCode default">inplace_vector&lt;T, N&gt;</code> is
<code class="sourceCode default">T::allocator_type</code> in both cases,
rather than
<code class="sourceCode default">std::allocator&lt;T&gt;</code>.</p>
<p>From these results, we can conclude that Option 1 produces no runtime
penalty for using the default allocator parameter; any penalty would be
borne exclusively by users that deliberately specify an allocator
argument.</p>
<h2 data-number="6.4" id="compile-time-results"><span class="header-section-number">6.4</span> Compile-Time Results<a href="#compile-time-results" class="self-link"></a></h2>
<p>The raw data shown in the tables below present the increase in
user-mode compile time for each option when compared to the <span class="citation" data-cites="P0843R10">[<a href="#ref-P0843R10" role="doc-biblioref">P0843R10</a>]</span> status quo. They show that
there is no appreciable compile-time penalty using any of the options
when the element type is not allocator aware (e.g.,
<code class="sourceCode default">inplace_vector&lt;int, N&gt;</code>).
Option 1 also had no penalty for allocator-aware element types when the
allocator type was left at the default
<code class="sourceCode default">std::allocator&lt;T&gt;</code>. Options
2 and 3 did exhibit a noticeable compile-time impact for allocator-aware
elements (e.g., <code class="sourceCode default">inplace_vector&lt;pmr::string, N&gt;</code>).
The additional compile time can be attributed to the machinery for
passing the allocator to the elements when an allocator is provided as
well as the metaprogramming needed to determine if
<code class="sourceCode default">T::allocator_type</code> exists.</p>
<p>From these results, we can conclude that the allocator-aware
<code class="sourceCode default">inplace_vector</code> described in
Option 1 imposes no significant compile-time cost compared to a
non-allocator-aware
<code class="sourceCode default">inplace_vector</code>.</p>
<p><strong>Raw compilation timing data</strong></p>
<p><em>Compilation times for P0843R10</em></p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Compiler</strong>
</div></th>
<th><div style="text-align:center">
<strong>Element Types
(<code class="sourceCode default">T</code>)</strong>
</div></th>
<th style="text-align: right;"><div style="text-align:center">
<strong>Compilation Time (s)</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>g++</td>
<td>Non-Allocator-Aware</td>
<td style="text-align: right;">3.37</td>
</tr>
<tr class="even">
<td>g++</td>
<td>Allocator-Aware</td>
<td style="text-align: right;">3.47</td>
</tr>
<tr class="odd">
<td>g++</td>
<td>Some AA, Some non-AA</td>
<td style="text-align: right;">5.14</td>
</tr>
<tr class="even">
<td>clang++</td>
<td>Non-Allocator-Aware</td>
<td style="text-align: right;">3.87</td>
</tr>
<tr class="odd">
<td>clang++</td>
<td>Allocator-Aware</td>
<td style="text-align: right;">4.32</td>
</tr>
<tr class="even">
<td>clang++</td>
<td>Some AA, Some non-AA</td>
<td style="text-align: right;">6.09</td>
</tr>
</tbody>
</table>
<p><em>Compilation times for Option 1</em></p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Compiler</strong>
</div></th>
<th><div style="text-align:center">
<strong>Element Types
(<code class="sourceCode default">T</code>)</strong>
</div></th>
<th style="text-align: right;"><div style="text-align:center">
<strong>Compilation Time (s)</strong>
</div></th>
<th style="text-align: right;"><div style="text-align:center">
<strong>Increase</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>g++</td>
<td>Non-Allocator-Aware</td>
<td style="text-align: right;">3.4</td>
<td style="text-align: right;">1%</td>
</tr>
<tr class="even">
<td>g++</td>
<td>Allocator-Aware</td>
<td style="text-align: right;">3.55</td>
<td style="text-align: right;">2%</td>
</tr>
<tr class="odd">
<td>g++</td>
<td>Some AA, Some non-AA</td>
<td style="text-align: right;">5.21</td>
<td style="text-align: right;">1%</td>
</tr>
<tr class="even">
<td>clang++</td>
<td>Non-Allocator-Aware</td>
<td style="text-align: right;">3.89</td>
<td style="text-align: right;">1%</td>
</tr>
<tr class="odd">
<td>clang++</td>
<td>Allocator-Aware</td>
<td style="text-align: right;">4.33</td>
<td style="text-align: right;">0%</td>
</tr>
<tr class="even">
<td>clang++</td>
<td>Some AA, Some non-AA</td>
<td style="text-align: right;">6.35</td>
<td style="text-align: right;">4%</td>
</tr>
</tbody>
</table>
<p><em>Compilation times for Option 2</em></p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Compiler</strong>
</div></th>
<th><div style="text-align:center">
<strong>Element Types
(<code class="sourceCode default">T</code>)</strong>
</div></th>
<th style="text-align: right;"><div style="text-align:center">
<strong>Compilation Time (s)</strong>
</div></th>
<th style="text-align: right;"><div style="text-align:center">
<strong>Increase</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>g++</td>
<td>Non-Allocator-Aware</td>
<td style="text-align: right;">3.34</td>
<td style="text-align: right;">-1%</td>
</tr>
<tr class="even">
<td>g++</td>
<td>Allocator-Aware</td>
<td style="text-align: right;">4.26</td>
<td style="text-align: right;">23%</td>
</tr>
<tr class="odd">
<td>g++</td>
<td>Some AA, Some non-AA</td>
<td style="text-align: right;">5.97</td>
<td style="text-align: right;">16%</td>
</tr>
<tr class="even">
<td>clang++</td>
<td>Non-Allocator-Aware</td>
<td style="text-align: right;">3.96</td>
<td style="text-align: right;">2%</td>
</tr>
<tr class="odd">
<td>clang++</td>
<td>Allocator-Aware</td>
<td style="text-align: right;">5.34</td>
<td style="text-align: right;">24%</td>
</tr>
<tr class="even">
<td>clang++</td>
<td>Some AA, Some non-AA</td>
<td style="text-align: right;">7.43</td>
<td style="text-align: right;">22%</td>
</tr>
</tbody>
</table>
<p><em>Compilation times for Option 3</em></p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Compiler</strong>
</div></th>
<th><div style="text-align:center">
<strong>Element Types
(<code class="sourceCode default">T</code>)</strong>
</div></th>
<th style="text-align: right;"><div style="text-align:center">
<strong>Compilation Time (s)</strong>
</div></th>
<th style="text-align: right;"><div style="text-align:center">
<strong>Increase</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>g++</td>
<td>Non-Allocator-Aware</td>
<td style="text-align: right;">3.44</td>
<td style="text-align: right;">2%</td>
</tr>
<tr class="even">
<td>g++</td>
<td>Allocator-Aware</td>
<td style="text-align: right;">4.29</td>
<td style="text-align: right;">24%</td>
</tr>
<tr class="odd">
<td>g++</td>
<td>Some AA, Some non-AA</td>
<td style="text-align: right;">5.89</td>
<td style="text-align: right;">15%</td>
</tr>
<tr class="even">
<td>clang++</td>
<td>Non-Allocator-Aware</td>
<td style="text-align: right;">3.92</td>
<td style="text-align: right;">1%</td>
</tr>
<tr class="odd">
<td>clang++</td>
<td>Allocator-Aware</td>
<td style="text-align: right;">5.35</td>
<td style="text-align: right;">24%</td>
</tr>
<tr class="even">
<td>clang++</td>
<td>Some AA, Some non-AA</td>
<td style="text-align: right;">7.34</td>
<td style="text-align: right;">21%</td>
</tr>
</tbody>
</table>
<h1 data-number="7" id="wording"><span class="header-section-number">7</span> Wording<a href="#wording" class="self-link"></a></h1>
<p>Wording will be provided after initial LEWG discussion.</p>
<p><strong>Design Decisions</strong></p>
<ul>
<li><p>Are we are interested in an allocator-aware
<code class="sourceCode default">inplace_vector</code>?</p></li>
<li><p>Which interface (Options 1 – 4) do we want?</p></li>
<li><p>How should the allocator be passed to the inserted elements: via
<em>uses-allocator construction</em> or via
<code class="sourceCode default">allocator_traits::construct</code>?</p></li>
</ul>
<p><strong>Procedural Decisions</strong></p>
<p>How should I specify wording? I can think of three possible ways
(listed from least to most effort).</p>
<ol type="1">
<li><p>Work with the authors of P0843 to integrate allocator
wording.</p></li>
<li><p>Create a separate diff against P0843 wording.</p></li>
<li><p>Wait until P0843 has been merged with the WP and create a diff
against the WP.</p></li>
</ol>
<h1 data-number="8" id="bibliography"><span class="header-section-number">8</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" role="doc-bibliography">
<div id="ref-P0429R3" class="csl-entry" role="doc-biblioentry">
[P0429R3] Zach Laine. 2016-08-31. A Standard flat_map. <a href="https://wg21.link/p0429r3"><div class="csl-block">https://wg21.link/p0429r3</div></a>
</div>
<div id="ref-P0843R10" class="csl-entry" role="doc-biblioentry">
[P0843R10] Gonzalo Brito Gadeschi, Timur Doumler, Nevin Liber, David
Sankel. 2024-02-12. inplace_vector. <a href="https://wg21.link/p0843r10"><div class="csl-block">https://wg21.link/p0843r10</div></a>
</div>
<div id="ref-P1222R0" class="csl-entry" role="doc-biblioentry">
[P1222R0] Zach Laine. 2018-10-02. A Standard flat_set. <a href="https://wg21.link/p1222r0"><div class="csl-block">https://wg21.link/p1222r0</div></a>
</div>
<div id="ref-P2035R0" class="csl-entry" role="doc-biblioentry">
[P2035R0] Pablo Halpern, John Lakos. 2020-01-13. Value Proposition:
Allocator-Aware (AA) Software. <a href="https://wg21.link/p2035r0"><div class="csl-block">https://wg21.link/p2035r0</div></a>
</div>
<div id="ref-P2047R7" class="csl-entry" role="doc-biblioentry">
[P2047R7] Nina Ranns, Pablo Halpern Ville Voutilainen. 2024-02-15. An
allocator-aware optional type. <a href="https://wg21.link/p2047r7"><div class="csl-block">https://wg21.link/p2047r7</div></a>
</div>
<div id="ref-P3002R1" class="csl-entry" role="doc-biblioentry">
[P3002R1] Pablo Halpern. 2024-02-15. Policies for Using Allocators in
New Library Classes. <a href="https://wg21.link/p3002r1"><div class="csl-block">https://wg21.link/p3002r1</div></a>
</div>
<div id="ref-P3153R0" class="csl-entry" role="doc-biblioentry">
[P3153R0] Nina Ranns, Pablo Halpern, Ville Voutilainen. 2024-02-15. An
allocator-aware variant type. <a href="https://wg21.link/p3153r0"><div class="csl-block">https://wg21.link/p3153r0</div></a>
</div>
</div>
<section class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>All citations to the Standard are to
working draft N4971 unless otherwise specified.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</div>
</div>
</body>
</html>
