<!DOCTYPE html>
<html>
<head>
<!-- 2024-03-22 Fri 16:22 -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Choices for ~make_optional~ and ~value_or()~</title>
<meta name="author" content="Steve Downey" />
<meta name="generator" content="Org Mode" />
<style>
  #content { max-width: 60em; margin: auto; }
  .title  { text-align: center;
             margin-bottom: .2em; }
  .subtitle { text-align: center;
              font-size: medium;
              font-weight: bold;
              margin-top:0; }
  .todo   { font-family: monospace; color: red; }
  .done   { font-family: monospace; color: green; }
  .priority { font-family: monospace; color: orange; }
  .tag    { background-color: #eee; font-family: monospace;
            padding: 2px; font-size: 80%; font-weight: normal; }
  .timestamp { color: #bebebe; }
  .timestamp-kwd { color: #5f9ea0; }
  .org-right  { margin-left: auto; margin-right: 0px;  text-align: right; }
  .org-left   { margin-left: 0px;  margin-right: auto; text-align: left; }
  .org-center { margin-left: auto; margin-right: auto; text-align: center; }
  .underline { text-decoration: underline; }
  #postamble p, #preamble p { font-size: 90%; margin: .2em; }
  p.verse { margin-left: 3%; }
  pre {
    border: 1px solid #e6e6e6;
    border-radius: 3px;
    background-color: #f2f2f2;
    padding: 8pt;
    font-family: monospace;
    overflow: auto;
    margin: 1.2em;
  }
  pre.src {
    position: relative;
    overflow: auto;
  }
  pre.src:before {
    display: none;
    position: absolute;
    top: -8px;
    right: 12px;
    padding: 3px;
    color: #555;
    background-color: #f2f2f299;
  }
  pre.src:hover:before { display: inline; margin-top: 14px;}
  /* Languages per Org manual */
  pre.src-asymptote:before { content: 'Asymptote'; }
  pre.src-awk:before { content: 'Awk'; }
  pre.src-authinfo::before { content: 'Authinfo'; }
  pre.src-C:before { content: 'C'; }
  /* pre.src-C++ doesn't work in CSS */
  pre.src-clojure:before { content: 'Clojure'; }
  pre.src-css:before { content: 'CSS'; }
  pre.src-D:before { content: 'D'; }
  pre.src-ditaa:before { content: 'ditaa'; }
  pre.src-dot:before { content: 'Graphviz'; }
  pre.src-calc:before { content: 'Emacs Calc'; }
  pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
  pre.src-fortran:before { content: 'Fortran'; }
  pre.src-gnuplot:before { content: 'gnuplot'; }
  pre.src-haskell:before { content: 'Haskell'; }
  pre.src-hledger:before { content: 'hledger'; }
  pre.src-java:before { content: 'Java'; }
  pre.src-js:before { content: 'Javascript'; }
  pre.src-latex:before { content: 'LaTeX'; }
  pre.src-ledger:before { content: 'Ledger'; }
  pre.src-lisp:before { content: 'Lisp'; }
  pre.src-lilypond:before { content: 'Lilypond'; }
  pre.src-lua:before { content: 'Lua'; }
  pre.src-matlab:before { content: 'MATLAB'; }
  pre.src-mscgen:before { content: 'Mscgen'; }
  pre.src-ocaml:before { content: 'Objective Caml'; }
  pre.src-octave:before { content: 'Octave'; }
  pre.src-org:before { content: 'Org mode'; }
  pre.src-oz:before { content: 'OZ'; }
  pre.src-plantuml:before { content: 'Plantuml'; }
  pre.src-processing:before { content: 'Processing.js'; }
  pre.src-python:before { content: 'Python'; }
  pre.src-R:before { content: 'R'; }
  pre.src-ruby:before { content: 'Ruby'; }
  pre.src-sass:before { content: 'Sass'; }
  pre.src-scheme:before { content: 'Scheme'; }
  pre.src-screen:before { content: 'Gnu Screen'; }
  pre.src-sed:before { content: 'Sed'; }
  pre.src-sh:before { content: 'shell'; }
  pre.src-sql:before { content: 'SQL'; }
  pre.src-sqlite:before { content: 'SQLite'; }
  /* additional languages in org.el's org-babel-load-languages alist */
  pre.src-forth:before { content: 'Forth'; }
  pre.src-io:before { content: 'IO'; }
  pre.src-J:before { content: 'J'; }
  pre.src-makefile:before { content: 'Makefile'; }
  pre.src-maxima:before { content: 'Maxima'; }
  pre.src-perl:before { content: 'Perl'; }
  pre.src-picolisp:before { content: 'Pico Lisp'; }
  pre.src-scala:before { content: 'Scala'; }
  pre.src-shell:before { content: 'Shell Script'; }
  pre.src-ebnf2ps:before { content: 'ebfn2ps'; }
  /* additional language identifiers per "defun org-babel-execute"
       in ob-*.el */
  pre.src-cpp:before  { content: 'C++'; }
  pre.src-abc:before  { content: 'ABC'; }
  pre.src-coq:before  { content: 'Coq'; }
  pre.src-groovy:before  { content: 'Groovy'; }
  /* additional language identifiers from org-babel-shell-names in
     ob-shell.el: ob-shell is the only babel language using a lambda to put
     the execution function name together. */
  pre.src-bash:before  { content: 'bash'; }
  pre.src-csh:before  { content: 'csh'; }
  pre.src-ash:before  { content: 'ash'; }
  pre.src-dash:before  { content: 'dash'; }
  pre.src-ksh:before  { content: 'ksh'; }
  pre.src-mksh:before  { content: 'mksh'; }
  pre.src-posh:before  { content: 'posh'; }
  /* Additional Emacs modes also supported by the LaTeX listings package */
  pre.src-ada:before { content: 'Ada'; }
  pre.src-asm:before { content: 'Assembler'; }
  pre.src-caml:before { content: 'Caml'; }
  pre.src-delphi:before { content: 'Delphi'; }
  pre.src-html:before { content: 'HTML'; }
  pre.src-idl:before { content: 'IDL'; }
  pre.src-mercury:before { content: 'Mercury'; }
  pre.src-metapost:before { content: 'MetaPost'; }
  pre.src-modula-2:before { content: 'Modula-2'; }
  pre.src-pascal:before { content: 'Pascal'; }
  pre.src-ps:before { content: 'PostScript'; }
  pre.src-prolog:before { content: 'Prolog'; }
  pre.src-simula:before { content: 'Simula'; }
  pre.src-tcl:before { content: 'tcl'; }
  pre.src-tex:before { content: 'TeX'; }
  pre.src-plain-tex:before { content: 'Plain TeX'; }
  pre.src-verilog:before { content: 'Verilog'; }
  pre.src-vhdl:before { content: 'VHDL'; }
  pre.src-xml:before { content: 'XML'; }
  pre.src-nxml:before { content: 'XML'; }
  /* add a generic configuration mode; LaTeX export needs an additional
     (add-to-list 'org-latex-listings-langs '(conf " ")) in .emacs */
  pre.src-conf:before { content: 'Configuration File'; }

  table { border-collapse:collapse; }
  caption.t-above { caption-side: top; }
  caption.t-bottom { caption-side: bottom; }
  td, th { vertical-align:top;  }
  th.org-right  { text-align: center;  }
  th.org-left   { text-align: center;   }
  th.org-center { text-align: center; }
  td.org-right  { text-align: right;  }
  td.org-left   { text-align: left;   }
  td.org-center { text-align: center; }
  dt { font-weight: bold; }
  .footpara { display: inline; }
  .footdef  { margin-bottom: 1em; }
  .figure { padding: 1em; }
  .figure p { text-align: center; }
  .equation-container {
    display: table;
    text-align: center;
    width: 100%;
  }
  .equation {
    vertical-align: middle;
  }
  .equation-label {
    display: table-cell;
    text-align: right;
    vertical-align: middle;
  }
  .inlinetask {
    padding: 10px;
    border: 2px solid gray;
    margin: 10px;
    background: #ffffcc;
  }
  #org-div-home-and-up
   { text-align: right; font-size: 70%; white-space: nowrap; }
  textarea { overflow-x: auto; }
  .linenr { font-size: smaller }
  .code-highlighted { background-color: #ffff00; }
  .org-info-js_info-navigation { border-style: none; }
  #org-info-js_console-label
    { font-size: 10px; font-weight: bold; white-space: nowrap; }
  .org-info-js_search-highlight
    { background-color: #ffff00; color: #000000; font-weight: bold; }
  .org-svg { }
</style>
<link rel="stylesheet" type="text/css" href="https://sdowney.org/css/wg21org.css"/>
<link rel="stylesheet" type="text/css" href="https://sdowney.org/css/modus-operandi-tinted.css"/>
<script>
// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&amp;dn=gpl-3.0.txt GPL-v3-or-Later
     function CodeHighlightOn(elem, id)
     {
       var target = document.getElementById(id);
       if(null != target) {
         elem.classList.add("code-highlighted");
         target.classList.add("code-highlighted");
       }
     }
     function CodeHighlightOff(elem, id)
     {
       var target = document.getElementById(id);
       if(null != target) {
         elem.classList.remove("code-highlighted");
         target.classList.remove("code-highlighted");
       }
     }
// @license-end
</script>
</head>
<body>
<div id="content">
<h1 class="title">Choices for <code>make_optional</code> and <code>value_or()</code></h1>

   <div data-fill-with="spec-metadata">
    <dl>
     <dt>Document #: <dd> P3199R0
     <dt>Date: <dd>2024-03-22
     <dt>Audience: <dd>LEWG
     <dt>Reply-to: <dd><a class="p-name fn u-email email" href="mailto:sdowney@gmail.com">Steve Downey &ltsdowney@gmail.com&gt</a>
     <dt>Source: <dd><a href="https://github.com/steve-downey/wg21org"/>https://github.com/steve-downey/wg21org</a>
                 <dd>homework-tokyo.org
                 <dd>tags/P3199R0-0-g6bc237b
    </dl>
   </div>
<nav id="toc" role="doc-toc">
<h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2>

<ul class="toc">
<li><a href="#orgb5ae5d4"><span class="secno">1 </span> <span class="content">From the design notes slides</span></a>
<ul class="toc">
<li><a href="#org72dbc2f"><span class="secno">1.1 </span> <span class="content">make_optional</span></a></li>
<li><a href="#org75f7b64"><span class="secno">1.2 </span> <span class="content">value_or</span></a></li>
</ul>
</li>
<li><a href="#orgf0479f8"><span class="secno">2 </span> <span class="content"><code>std::make_optional</code> in the context of <code>optional&lt;T&amp;&gt;</code></span></a>
<ul class="toc">
<li><a href="#orgdebe292"><span class="secno">2.1 </span> <span class="content">Recommend <b>Do Nothing</b></span></a></li>
</ul>
</li>
<li><a href="#org48398b0"><span class="secno">3 </span> <span class="content"><code>std::optional&lt;T&amp;&gt;::value_or</code></span></a>
<ul class="toc">
<li><a href="#orgd3e2502"><span class="secno">3.1 </span> <span class="content">Standard for <code>optional&lt;T&gt;::value_or</code></span></a></li>
<li><a href="#org57bcca3"><span class="secno">3.2 </span> <span class="content">Boost</span></a></li>
<li><a href="#org333a622"><span class="secno">3.3 </span> <span class="content">Tl-optional</span></a></li>
<li><a href="#org751c74b"><span class="secno">3.4 </span> <span class="content">Flux</span></a></li>
<li><a href="#orge3a6424"><span class="secno">3.5 </span> <span class="content">Think-Cell</span></a></li>
<li><a href="#orgb243b9f"><span class="secno">3.6 </span> <span class="content">Summary</span></a></li>
<li><a href="#orga2a9edd"><span class="secno">3.7 </span> <span class="content">Proposal</span></a>
<ul class="toc">
<li><a href="#orgf36d3a0"><span class="secno">3.7.1 </span> <span class="content">Examples</span></a></li>
<li><a href="#orgc47283b"><span class="secno">3.7.2 </span> <span class="content">Motivation for reference returning value_or</span></a></li>
<li><a href="#org26f16e0"><span class="secno">3.7.3 </span> <span class="content">Discussion</span></a></li>
<li><a href="#orgd24dbe5"><span class="secno">3.7.4 </span> <span class="content">Proposal</span></a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#org8d1b1d6"><span class="secno">4 </span> <span class="content">References</span></a></li>
</ul>

</nav>
<div class="abstract" id="org13009ac">
<p>
Abstract: Homework: Review options for std::make_optional and std::optional&lt;T&amp;&gt;::value_or()
</p>

</div>
<div id="outline-container-orgb5ae5d4" class="outline-2">
<h2 id="orgb5ae5d4"><span class="section-number-2">1.</span> From the design notes slides</h2>
<div class="outline-text-2" id="text-1">
<p>
Recap of 2024-03-20 presentation slides that did not have consensus.
</p>
</div>
<div id="outline-container-org72dbc2f" class="outline-3">
<h3 id="org72dbc2f"><span class="section-number-3">1.1.</span> make_optional</h3>
<div class="outline-text-3" id="text-1-1">
<ul class="org-ul">
<li>Because of existing code, <code>make_optional&lt;T&amp;&gt;</code> must return optional&lt;T&gt; rather than optional&lt;T&amp;&gt;.</li>
<li>Returning optional&lt;T&amp;&gt; is consistent and defensible, and a few optional implementations in production make this choice.</li>
<li>It is, however, quite easy to construct a make_optional expression that deduces a different category causing possibly dangerous changes to code.</li>
</ul>
</div>
</div>
<div id="outline-container-org75f7b64" class="outline-3">
<h3 id="org75f7b64"><span class="section-number-3">1.2.</span> value_or</h3>
<div class="outline-text-3" id="text-1-2">
<p>
Have <code>value_or</code> return a <code>T&amp;</code>.
</p>

<p>
A reference so that there is a shared referent for the or side as well as the optional.
</p>

<p>
Check that the supplied value can be bound to a <code>T&amp;</code>.
</p>
</div>
</div>
</div>
<div id="outline-container-orgf0479f8" class="outline-2">
<h2 id="orgf0479f8"><span class="section-number-2">2.</span> <code>std::make_optional</code> in the context of <code>optional&lt;T&amp;&gt;</code></h2>
<div class="outline-text-2" id="text-2">
<p>
Current specification:
</p>
<div class="org-src-container">
<pre class="src src-C++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">class</span> <span class="org-type">T</span>&gt; <span class="org-keyword">constexpr</span> <span class="org-type">optional</span>&lt;<span class="org-type">decay_t</span>&lt;<span class="org-type">T</span>&gt;&gt; <span class="org-function-name">make_optional</span>(<span class="org-type">T</span>&amp;&amp; <span class="org-variable-name">v</span>);
<span class="org-comment-delimiter">// </span><span class="org-comment">Returns: optional&lt;decay_t&lt;T&gt;&gt;(std&#8203;::&#8203;forward&lt;T&gt;(v)).</span>

<span class="org-keyword">template</span>&lt;<span class="org-keyword">class</span> <span class="org-type">T</span>, <span class="org-keyword">class</span>...<span class="org-type">Args</span>&gt;
  <span class="org-keyword">constexpr</span> <span class="org-type">optional</span>&lt;<span class="org-type">T</span>&gt; <span class="org-function-name">make_optional</span>(<span class="org-type">Args</span>&amp;&amp;... <span class="org-variable-name">args</span>);
<span class="org-comment-delimiter">// </span><span class="org-comment">Effects: Equivalent to: return optional&lt;T&gt;(in_place, std&#8203;::&#8203;forward&lt;Args&gt;(args)...);</span>

<span class="org-keyword">template</span>&lt;<span class="org-keyword">class</span> <span class="org-type">T</span>, <span class="org-keyword">class</span> <span class="org-type">U</span>, <span class="org-keyword">class</span>... <span class="org-type">Args</span>&gt;
  <span class="org-keyword">constexpr</span> <span class="org-type">optional</span>&lt;<span class="org-type">T</span>&gt; <span class="org-function-name">make_optional</span>(<span class="org-type">initializer_list</span>&lt;<span class="org-type">U</span>&gt; <span class="org-variable-name">il</span>, <span class="org-type">Args</span>&amp;&amp;... <span class="org-variable-name">args</span>);
<span class="org-comment-delimiter">// </span><span class="org-comment">Effects: Equivalent to: return optional&lt;T&gt;(in_place, il, std&#8203;::&#8203;forward&lt;Args&gt;(args)...);</span>
</pre>
</div>


<p>
The second two forms are disallowed for std::optional&lt;T&amp;&gt; because in_place with multiple arguments does not make sense.
</p>

<div class="org-src-container">
<pre class="src src-C++"><span class="org-preprocessor">#include</span> <span class="org-string">&lt;optional&gt;</span>

<span class="org-keyword">struct</span> <span class="org-type">MyStruct</span> {};

<span class="org-type">MyStruct</span>&amp; <span class="org-function-name">func</span>();

static_assert(<span class="org-constant">std</span>::<span class="org-type">is_same_v</span>&lt;
                  <span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">MyStruct</span>&gt;,
                  <span class="org-keyword">decltype</span>(<span class="org-constant">std</span>::make_optional(
                      MyStruct{}))&gt; == <span class="org-constant">true</span>);

static_assert(<span class="org-constant">std</span>::<span class="org-type">is_same_v</span>&lt;
                  <span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">MyStruct</span>&gt;,
                  <span class="org-keyword">decltype</span>(<span class="org-constant">std</span>::make_optional(
                      func()))&gt; == <span class="org-constant">true</span>);

<span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">MyStruct</span>&gt; <span class="org-variable-name">r1</span> =
    <span class="org-constant">std</span>::make_optional&lt;<span class="org-type">MyStruct</span>&gt;(func());

<span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">MyStruct</span>&gt; <span class="org-variable-name">r1a</span> =
    <span class="org-constant">std</span>::make_optional&lt;<span class="org-type">MyStruct</span>&amp;&gt;(func());

<span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">MyStruct</span>&gt; <span class="org-variable-name">r1b</span> =
    <span class="org-constant">std</span>::make_optional(func());


<span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">MyStruct</span>&gt; <span class="org-variable-name">r2</span> =
    <span class="org-constant">std</span>::make_optional&lt;<span class="org-type">MyStruct</span>&gt;(
        <span class="org-constant">std</span>::move(MyStruct{}));

<span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">MyStruct</span>&gt; <span class="org-variable-name">r2a</span> =
    <span class="org-constant">std</span>::make_optional&lt;<span class="org-type">MyStruct</span>&amp;&amp;&gt;(
        <span class="org-constant">std</span>::move(MyStruct{}));
</pre>
</div>

<p>
<a href="https://compiler-explorer.com/z/no7znrz9v">https://compiler-explorer.com/z/no7znrz9v</a>
</p>

<p>
We can currently spell as well as deduce <code>MyStruct&amp;</code> and <code>MyStruct&amp;&amp;</code> for <code>make_optional</code> and the result is a <code>std::optional&lt;T&gt;</code>.
</p>

<p>
I think it is clear that changing the return type for a <code>make_optional</code> on an expression that has a reference type from a <code>std::optional&lt;T&gt;</code> to a <code>std::optional&lt;T&amp;&gt;</code> would not be acceptable in existing code. The code might fail to compile because we forbid dangling temporary binding, but succesful compilation might be even worse.
</p>

<p>
It's not clear right now that people spelling the template with a <code>T&amp;</code> are doing so with great deliberateness. There is certainly the possibility that users may be confused and try to get an <code>optional&lt;T&amp;&gt;</code> out of <code>make_optional</code>, but failure should be generally quickly visible as there is no viable path to construct or assign a <code>optional&lt;T&gt;</code> to an <code>optional&lt;T&amp;&gt;</code>. Conversions do permit an <code>optional&lt;T&gt;</code> to be initialized from an <code>optional&lt;T&amp;&gt;</code>, as <code>optional</code> is fairly permissive about conversions, and this seems mostly desirable.
</p>

<div class="org-src-container">
<pre class="src src-C++">    <span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">int</span>&gt; <span class="org-variable-name">x</span>;
    <span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">int</span>&amp;&gt; <span class="org-variable-name">x2</span> = x;   <span class="org-comment-delimiter">//</span><span class="org-comment">fails</span>
    <span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">int</span>&amp;&gt; <span class="org-variable-name">x3</span>{x};    <span class="org-comment-delimiter">//</span><span class="org-comment">fails</span>
    i3 = x;                       <span class="org-comment-delimiter">//</span><span class="org-comment">fails</span>

    <span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">int</span>&amp;&gt; <span class="org-variable-name">k</span>;
    <span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">int</span>&amp;&gt; <span class="org-variable-name">y</span> = k;    <span class="org-comment-delimiter">// </span><span class="org-comment">compiles</span>
    <span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">int</span>&amp;&gt; <span class="org-variable-name">y2</span>{k};    <span class="org-comment-delimiter">// </span><span class="org-comment">compiles</span>
    y = k;                        <span class="org-comment-delimiter">// </span><span class="org-comment">compiles</span>

</pre>
</div>

<p>
Given the adopted policy regarding <code>[[nodiscard]]</code> I am not sure we should mandate a diagnostic at this point, without at least more feedback from standard library implementors. Policy paper to come.
</p>
</div>
<div id="outline-container-orgdebe292" class="outline-3">
<h3 id="orgdebe292"><span class="section-number-3">2.1.</span> Recommend <b>Do Nothing</b></h3>
<div class="outline-text-3" id="text-2-1">
<p>
Make no changes to the behavior or compilation of std::make_optional. It's not clear right now we need a <code>make_optional_ref</code> in place of the existing constructors. There's no constructor confusion, or multi-arg emplace. I think I would need evidence that <code>std::optional&lt;MyType&amp;&gt;{}</code> is not sufficient.
</p>
</div>
</div>
</div>
<div id="outline-container-org48398b0" class="outline-2">
<h2 id="org48398b0"><span class="section-number-2">3.</span> <code>std::optional&lt;T&amp;&gt;::value_or</code></h2>
<div class="outline-text-2" id="text-3">
<p>
There are different implementations in the optionals in the wild that both support references and support <code>value_or</code>.
</p>
</div>
<div id="outline-container-orgd3e2502" class="outline-3">
<h3 id="orgd3e2502"><span class="section-number-3">3.1.</span> Standard for <code>optional&lt;T&gt;::value_or</code></h3>
<div class="outline-text-3" id="text-3-1">
<p>
(<a href="#citeproc_bib_item_6">Köppe 2022</a>)
</p>

<div class="org-src-container">
<pre class="src src-C++"><span class="org-keyword">template</span>&lt;<span class="org-keyword">class</span> <span class="org-type">U</span>&gt; <span class="org-keyword">constexpr</span> <span class="org-type">T</span> <span class="org-function-name">value_or</span>(<span class="org-type">U</span>&amp;&amp; <span class="org-variable-name">v</span>) <span class="org-keyword">const</span> &amp;;

<span class="org-comment-delimiter">// </span><span class="org-comment">Mandates: is_copy_constructible_v&lt;T&gt; &amp;&amp; is_convertible_v&lt;U&amp;&amp;, T&gt; is true.</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">Effects: Equivalent to:</span>
<span class="org-comment-delimiter">//   </span><span class="org-comment">return has_value() ? **this : static_cast&lt;T&gt;(std::forward&lt;U&gt;(v));</span>

<span class="org-keyword">template</span>&lt;<span class="org-keyword">class</span> <span class="org-type">U</span>&gt; <span class="org-keyword">constexpr</span> <span class="org-type">T</span> <span class="org-function-name">value_or</span>(<span class="org-type">U</span>&amp;&amp; <span class="org-variable-name">v</span>) &amp;&amp;;

<span class="org-comment-delimiter">// </span><span class="org-comment">Mandates: is_move_constructible_v&lt;T&gt; &amp;&amp; is_convertible_v&lt;U&amp;&amp;, T&gt; is true.</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">Effects: Equivalent to:</span>
<span class="org-comment-delimiter">//  </span><span class="org-comment">return has_value() ? std::move(**this) : static_cast&lt;T&gt;(std::forward&lt;U&gt;(v));</span>
</pre>
</div>

<p>
Note that for <code>optional&lt;T&gt;</code> moving the value out of a held value in an rvalue-ref optional is entirely reasonable.
</p>

<p>
It is not for a reference semantic optional.
</p>
</div>
</div>
<div id="outline-container-org57bcca3" class="outline-3">
<h3 id="org57bcca3"><span class="section-number-3">3.2.</span> Boost</h3>
<div class="outline-text-3" id="text-3-2">
<p>
(<a href="#citeproc_bib_item_1">Boost, n.d.</a>)
</p>
<div class="org-src-container">
<pre class="src src-C++">
<span class="org-keyword">template</span>&lt;<span class="org-keyword">class</span> <span class="org-type">U</span>&gt; <span class="org-type">T</span> <span class="org-constant">optional</span>&lt;T&gt;::<span class="org-function-name">value_or</span>(<span class="org-type">U</span> &amp;&amp; <span class="org-variable-name">v</span>) <span class="org-keyword">const</span>&amp; ;

<span class="org-comment-delimiter">// </span><span class="org-comment">Effects: Equivalent to if (*this) return **this; else return std::forward&lt;U&gt;(v);.</span>

<span class="org-comment-delimiter">// </span><span class="org-comment">Remarks: If T is not CopyConstructible or U &amp;&amp; is not convertible to T, the</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">program is ill-formed.  Notes: On compilers that do not support</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">ref-qualifiers on member functions this overload is replaced with the</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">const-qualified member function. On compilers without rvalue reference</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">support the type of v becomes U const&amp;.</span>

<span class="org-keyword">template</span>&lt;<span class="org-keyword">class</span> <span class="org-type">U</span>&gt; <span class="org-type">T</span> <span class="org-constant">optional</span>&lt;T&gt;::<span class="org-function-name">value_or</span>(<span class="org-type">U</span> &amp;&amp; <span class="org-variable-name">v</span>) &amp;&amp; ;

<span class="org-comment-delimiter">// </span><span class="org-comment">Effects: Equivalent to if (*this) return std::move(**this); else return std::forward&lt;U&gt;(v);.</span>

<span class="org-comment-delimiter">// </span><span class="org-comment">Remarks: If T is not MoveConstructible or U &amp;&amp; is not convertible to T, the</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">program is ill-formed.  Notes: On compilers that do not support</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">ref-qualifiers on member functions this overload is not present.</span>

<span class="org-keyword">template</span>&lt;<span class="org-keyword">class</span> <span class="org-type">R</span>&gt; <span class="org-type">T</span>&amp; <span class="org-constant">optional</span>&lt;<span class="org-type">T</span>&amp;&gt;::<span class="org-function-name">value_or</span>( <span class="org-type">R</span>&amp;&amp; <span class="org-variable-name">r</span> ) <span class="org-keyword">const</span> <span class="org-keyword">noexcept</span>;

<span class="org-comment-delimiter">// </span><span class="org-comment">Effects: Equivalent to if (*this) return **this; else return r;.</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">Remarks: Unless R is an lvalue reference, the program is ill-formed.</span>
</pre>
</div>
</div>
</div>
<div id="outline-container-org333a622" class="outline-3">
<h3 id="org333a622"><span class="section-number-3">3.3.</span> Tl-optional</h3>
<div class="outline-text-3" id="text-3-3">
<p>
(<a href="#citeproc_bib_item_2">Brand, n.d.</a>)
</p>
<div class="org-src-container">
<pre class="src src-C++"> <span class="org-keyword">template</span> &lt;<span class="org-keyword">class</span> <span class="org-type">U</span>&gt; <span class="org-keyword">constexpr</span> <span class="org-type">T</span> <span class="org-constant">optional</span>&lt;<span class="org-type">T</span>&amp;&gt;::<span class="org-function-name">value_or</span>(<span class="org-type">U</span> &amp;&amp;<span class="org-variable-name">u</span>) &amp;&amp; <span class="org-keyword">noexcept</span>;
</pre>
</div>
<p>
Returns a <code>T</code> rather than a <code>T&amp;</code>
</p>
</div>
</div>
<div id="outline-container-org751c74b" class="outline-3">
<h3 id="org751c74b"><span class="section-number-3">3.4.</span> Flux</h3>
<div class="outline-text-3" id="text-3-4">
<p>
(<a href="#citeproc_bib_item_3">Brindle, n.d.</a>)
This is from Tristan Brindle's tristanbrindle.com/flux/
</p>

<div class="org-src-container">
<pre class="src src-C++"><span class="org-preprocessor">#define</span> <span class="org-function-name">FLUX_FWD</span>(<span class="org-variable-name">x</span>) <span class="org-keyword">static_cast</span>&lt;<span class="org-keyword">decltype</span>(x)&amp;&amp;&gt;(x)
<span class="org-comment-delimiter">//</span><span class="org-comment">...</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">optional&lt;T&amp;&gt;</span>
   [[nodiscard]]
    <span class="org-keyword">constexpr</span> <span class="org-keyword">auto</span> <span class="org-function-name">value_unchecked</span>() <span class="org-keyword">const</span> <span class="org-keyword">noexcept</span> -&gt; <span class="org-type">T</span>&amp; { <span class="org-keyword">return</span> *ptr_; }

    [[nodiscard]]
    <span class="org-keyword">constexpr</span> <span class="org-keyword">auto</span> <span class="org-function-name">value_or</span>(<span class="org-keyword">auto</span>&amp;&amp; <span class="org-variable-name">alt</span>) <span class="org-keyword">const</span>
        -&gt; <span class="org-keyword">decltype</span>(has_value() ? value_unchecked() : FLUX_FWD(alt))
    {
        <span class="org-keyword">return</span> has_value() ? value_unchecked() : FLUX_FWD(alt);
    }

</pre>
</div>
<p>
Flux returns references, but effectively returns a common reference type.
</p>

<p>
Note that all implementations return a <code>T&amp;</code> from <code>value()</code>, as well as for <code>operator*()</code> for all template instantiations. Arguing that value_or should return T because `value` is plausible, but not supportable for existing APIs.
</p>
</div>
</div>
<div id="outline-container-orge3a6424" class="outline-3">
<h3 id="orge3a6424"><span class="section-number-3">3.5.</span> Think-Cell</h3>
<div class="outline-text-3" id="text-3-5">
<p>
(<a href="#citeproc_bib_item_5">GmbH, n.d.</a>)
</p>

<p>
<a href="https://github.com/think-cell/think-cell-library/">https://github.com/think-cell/think-cell-library/</a>
</p>

<p>
value_or of both <code>optional&lt;T&gt;</code> and <code>optional&lt;T&amp;&gt;</code> returns <code>tc::common_reference&lt;decltype(value()), U&amp;&amp;&gt;</code>, which is like std::common_reference, but doesn't compile for e.g. long and unsigned long).
</p>

<p>
see:
</p>
<ul class="org-ul">
<li><a href="https://github.com/think-cell/think-cell-library/blob/b9c84dd7fc926fad80829ed49705fa51afe36e87/tc/optional.h#L270">tc optional value_or</a></li>
<li><a href="https://github.com/think-cell/think-cell-library/blob/b9c84dd7fc926fad80829ed49705fa51afe36e87/tc/base/conditional.h#L18">Macro definition used</a></li>
<li><a href="https://github.com/think-cell/think-cell-library/blob/b9c84dd7fc926fad80829ed49705fa51afe36e87/tc/base/type_traits_fwd.h#L822">tc common reference</a></li>
</ul>
</div>
</div>
<div id="outline-container-orgb243b9f" class="outline-3">
<h3 id="orgb243b9f"><span class="section-number-3">3.6.</span> Summary</h3>
<div class="outline-text-3" id="text-3-6">
<table>


<colgroup>
<col  class="org-left">

<col  class="org-left">
</colgroup>
<thead>
<tr>
<th scope="col" class="org-left">Impl</th>
<th scope="col" class="org-left">Behavior</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-left">Standard</td>
<td class="org-left">optional&lt;T&gt;::value_or returns a T</td>
</tr>

<tr>
<td class="org-left">Boost</td>
<td class="org-left">optional&lt;T&gt;::value_or returns a T</td>
</tr>

<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">optional&lt;T&amp;&gt;::value_or returns a T&amp;</td>
</tr>

<tr>
<td class="org-left">TL</td>
<td class="org-left">optional&lt;T&gt;::value_or returns a T</td>
</tr>

<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">optional&lt;T&amp;&gt;::value_or returns a T</td>
</tr>

<tr>
<td class="org-left">Flux</td>
<td class="org-left">returns result of ternary, similar to common_reference</td>
</tr>

<tr>
<td class="org-left">Think-cell</td>
<td class="org-left">returns common_reference, with some caveats</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="outline-container-orga2a9edd" class="outline-3">
<h3 id="orga2a9edd"><span class="section-number-3">3.7.</span> Proposal</h3>
<div class="outline-text-3" id="text-3-7">
<p>
Last night on Mattermost Tomasz Kamiński proposed
</p>
<div class="org-src-container">
<pre class="src src-C++">    <span class="org-keyword">template</span> &lt;<span class="org-keyword">class</span> <span class="org-type">U</span>, <span class="org-keyword">class</span> <span class="org-type">R</span> = <span class="org-constant">std</span>::<span class="org-type">common_reference_t</span>&lt;<span class="org-type">T</span>&amp;, <span class="org-type">U</span>&amp;&amp;&gt;&gt;
    <span class="org-keyword">auto</span> <span class="org-function-name">value_or</span>(<span class="org-type">U</span>&amp;&amp; <span class="org-variable-name">v</span>) <span class="org-keyword">const</span> -&gt; <span class="org-type">R</span> {
        static_assert(<span class="org-negation-char">!</span><span class="org-constant">std</span>::<span class="org-type">reference_constructs_from_temporary_v</span>&lt;<span class="org-type">R</span>, <span class="org-type">U</span>&gt;);
        static_assert(<span class="org-negation-char">!</span><span class="org-constant">std</span>::<span class="org-type">reference_constructs_from_temporary_v</span>&lt;<span class="org-type">R</span>, <span class="org-type">T</span>&amp;&gt;);
        <span class="org-keyword">return</span> ptr ? <span class="org-keyword">static_cast</span>&lt;<span class="org-type">R</span>&gt;(*ptr) : <span class="org-keyword">static_cast</span>&lt;<span class="org-type">R</span>&gt;((<span class="org-type">U</span>&amp;&amp;)v);
    }
</pre>
</div>
</div>
<div id="outline-container-orgf36d3a0" class="outline-4">
<h4 id="orgf36d3a0"><span class="section-number-4">3.7.1.</span> Examples</h4>
<div class="outline-text-4" id="text-3-7-1">
<div class="org-src-container">
<pre class="src src-C++">    <span class="org-type">optional</span>&lt;<span class="org-type">int</span>&amp;&gt; <span class="org-variable-name">o</span>; <span class="org-comment-delimiter">// </span><span class="org-comment">disengaged optional&lt;int&amp;&gt;</span>
    <span class="org-type">long</span> <span class="org-variable-name">i</span>{42};
    <span class="org-keyword">auto</span>&amp;&amp; <span class="org-variable-name">val</span> = o.value_or(i);
    static_assert(<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-keyword">decltype</span>(o.value()), <span class="org-type">int</span>&amp;&gt;);
    static_assert(<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-keyword">decltype</span>(o.value_or(i)), <span class="org-type">long</span>&gt;);

    <span class="org-type">optional</span>&lt;<span class="org-type">base</span>&amp;&gt; <span class="org-variable-name">b</span>;
    <span class="org-type">derived</span> <span class="org-variable-name">d</span>;
    static_assert(<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-keyword">decltype</span>(b.value()), <span class="org-type">base</span>&amp;&gt;);
    static_assert(<span class="org-constant">std</span>::<span class="org-type">same_as</span>&lt;<span class="org-keyword">decltype</span>(b.value_or(d)), <span class="org-type">base</span>&amp;&gt;);

</pre>
</div>
<p>
<a href="https://godbolt.org/z/rWo7Wvd6b">https://godbolt.org/z/rWo7Wvd6b</a>
</p>
</div>
</div>
<div id="outline-container-orgc47283b" class="outline-4">
<h4 id="orgc47283b"><span class="section-number-4">3.7.2.</span> Motivation for reference returning value_or</h4>
<div class="outline-text-4" id="text-3-7-2">
<div class="org-src-container">
<pre class="src src-C++">
<span class="org-keyword">struct</span> <span class="org-type">Logger</span> {
    <span class="org-keyword">virtual</span> <span class="org-type">void</span> <span class="org-function-name">debug</span>(<span class="org-constant">std</span>::<span class="org-type">string_view</span> <span class="org-variable-name">sv</span>) = 0;
};

<span class="org-keyword">struct</span> <span class="org-type">DefaultLogger</span> : <span class="org-keyword">public</span> <span class="org-type">Logger</span> {
    <span class="org-function-name">DefaultLogger</span>() {}
    <span class="org-function-name">DefaultLogger</span>(<span class="org-keyword">const</span> <span class="org-type">DefaultLogger</span> &amp; <span class="org-variable-name">l</span>) = <span class="org-keyword">delete</span>;
    <span class="org-keyword">virtual</span> <span class="org-type">void</span> <span class="org-function-name">debug</span>(<span class="org-constant">std</span>::<span class="org-type">string_view</span> <span class="org-variable-name">sv</span>) <span class="org-keyword">override</span> {}
};

<span class="org-type">DefaultLogger</span>&amp; <span class="org-function-name">getDefaultLogger</span>() {
    <span class="org-keyword">static</span> <span class="org-type">DefaultLogger</span> <span class="org-variable-name">dl</span>;
    <span class="org-keyword">return</span> dl;
}

<span class="org-type">Logger</span>&amp; <span class="org-function-name">getLogger</span>(<span class="org-type">optional</span>&lt;<span class="org-type">Logger</span>&amp;&gt; <span class="org-variable-name">logger</span>) {
    <span class="org-keyword">return</span> l.value_or(getDefaultLogger());
}
</pre>
</div>
</div>
</div>
<div id="outline-container-org26f16e0" class="outline-4">
<h4 id="org26f16e0"><span class="section-number-4">3.7.3.</span> Discussion</h4>
<div class="outline-text-4" id="text-3-7-3">
<p>
I believe that std::optional&lt;T&gt;::value_or returning a T is an unfortunate and unfixable mistake. Others believe that instead there ought to have been a <code>value()</code> returning <code>T</code>, and a <code>ref()</code> returning <code>T&amp;</code>. The ship for changing those has long since sailed.
</p>

<p>
I believe the use case of alternative references is important, and should be supported. I have been conviced that <code>value_or</code> is not an available name for that function.
</p>

<p>
However, given the state of <code>std::optional&lt;T&gt;::value_or</code>, I think this function needs to be called <code>ref_or</code>.
</p>
</div>
</div>
<div id="outline-container-orgd24dbe5" class="outline-4">
<h4 id="orgd24dbe5"><span class="section-number-4">3.7.4.</span> Proposal</h4>
<div class="outline-text-4" id="text-3-7-4">
<p>
We should instead remove <code>value_or</code>. There is no clear correct answer that works generically. Conversions from <code>std::optional&lt;reference_wrapper&lt;T&gt;&gt;</code> already need to do some work, as do conversions from any other existing optional. Making that work clear is a benefit.
</p>

<p>
As a fallback, have <code>value_or</code> return a prvalue, a <code>T</code>. A <code>T&amp;</code>, instead of <code>std::common_reference_t&lt;T&amp;, U&gt;</code>, excludes to many reasonable cases.
</p>

<p>

</p>
</div>
</div>
</div>
</div>
<div id="outline-container-org8d1b1d6" class="outline-2">
<h2 id="org8d1b1d6"><span class="section-number-2">4.</span> References</h2>
<div class="outline-text-2" id="text-4">
<style>.csl-entry{text-indent: -1.5em; margin-left: 1.5em;}</style><div class="csl-bib-body">
  <div class="csl-entry"><a id="citeproc_bib_item_1"></a>Boost. n.d. “Detailed Semantics - Optional Values - 1.82.0.” <a href="https://www.boost.org/doc/libs/1_82_0/libs/optional/doc/html/boost_optional/reference/header__boost_optional_optional_hpp_/detailed_semantics___optional_values.html#reference_optional_value_or">https://www.boost.org/doc/libs/1_82_0/libs/optional/doc/html/boost_optional/reference/header__boost_optional_optional_hpp_/detailed_semantics___optional_values.html#reference_optional_value_or</a>.</div>
  <div class="csl-entry"><a id="citeproc_bib_item_2"></a>Brand, Sy. n.d. “TartanLlama/Optional: C++11/14/17 Std:Optional with Functional-Style Extensions and Reference Support.” <a href="https://github.com/TartanLlama/optional">https://github.com/TartanLlama/optional</a>.</div>
  <div class="csl-entry"><a id="citeproc_bib_item_3"></a>Brindle, Tristan. n.d. “Tcbrindle/Flux: A C++20 Library for Sequence-Orientated Programming.” <a href="https://github.com/tcbrindle/flux">https://github.com/tcbrindle/flux</a>.</div>
  <div class="csl-entry"><a id="citeproc_bib_item_4"></a>Downey, Steve, and Peter Sommerlad. 2024. “P2988R1: Std:Optional.” https://wg21.link/p2988r1; WG21.</div>
  <div class="csl-entry"><a id="citeproc_bib_item_5"></a>GmbH, think-cell Software. n.d. “Think-Cell/Think-Cell-Library: Think-Cell Core Library.” <a href="https://github.com/think-cell/think-cell-library/">https://github.com/think-cell/think-cell-library/</a>.</div>
  <div class="csl-entry"><a id="citeproc_bib_item_6"></a>Köppe, Thomas. 2022. “N4928: Working Draft, Standard for Programming Language c++.” https://wg21.link/n4928; WG21.</div>
</div>

<p>
Exported: 2024-03-22 16:22:48
</p>

<script>
(function() {
  "use strict";
  var collapseSidebarText = '<span aria-hidden="true">?</span> '
                          + '<span>Collapse Sidebar</span>';
  var expandSidebarText   = '<span aria-hidden="true">?</span> '
                          + '<span>Pop Out Sidebar</span>';
  var tocJumpText         = '<span aria-hidden="true">?</span> '
                          + '<span>Jump to Table of Contents</span>';

  var sidebarMedia = window.matchMedia('screen and (min-width: 78em)');
  var autoToggle   = function(e){ toggleSidebar(e.matches) };
  if(sidebarMedia.addListener) {
    sidebarMedia.addListener(autoToggle);
  }

  function toggleSidebar(on) {
    if (on == undefined) {
      on = !document.body.classList.contains('toc-sidebar');
    }

    /* Dont scroll to compensate for the ToC if were above it already. */
    var headY = 0;
    var head = document.querySelector('.head');
    if (head) {
      // terrible approx of "top of ToC"
      headY += head.offsetTop + head.offsetHeight;
    }
    var skipScroll = window.scrollY < headY;

    var toggle = document.getElementById('toc-toggle');
    var tocNav = document.getElementById('toc');
    if (on) {
      var tocHeight = tocNav.offsetHeight;
      document.body.classList.add('toc-sidebar');
      document.body.classList.remove('toc-inline');
      toggle.innerHTML = collapseSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, 0 - tocHeight);
      }
      tocNav.focus();
      sidebarMedia.addListener(autoToggle); // auto-collapse when out of room
    }
    else {
      document.body.classList.add('toc-inline');
      document.body.classList.remove('toc-sidebar');
      toggle.innerHTML = expandSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, tocNav.offsetHeight);
      }
      if (toggle.matches(':hover')) {
        /* Unfocus button when not using keyboard navigation,
           because I dont know where else to send the focus. */
        toggle.blur();
      }
    }
  }

  function createSidebarToggle() {
    /* Create the sidebar toggle in JS; it shouldnt exist when JS is off. */
    var toggle = document.createElement('a');
      /* This should probably be a button, but appearance isnt standards-track.*/
    toggle.id = 'toc-toggle';
    toggle.class = 'toc-toggle';
    toggle.href = '#toc';
    toggle.innerHTML = collapseSidebarText;

    sidebarMedia.addListener(autoToggle);
    var toggler = function(e) {
      e.preventDefault();
      sidebarMedia.removeListener(autoToggle); // persist explicit off states
      toggleSidebar();
      return false;
    }
    toggle.addEventListener('click', toggler, false);


    /* Get <nav id=toc-nav>, or make it if we dont have one. */
    var tocNav = document.getElementById('toc-nav');
    if (!tocNav) {
      tocNav = document.createElement('p');
      tocNav.id = 'toc-nav';
      /* Prepend for better keyboard navigation */
      document.body.insertBefore(tocNav, document.body.firstChild);
    }
    /* While were at it, make sure we have a Jump to Toc link. */
    var tocJump = document.getElementById('toc-jump');
    if (!tocJump) {
      tocJump = document.createElement('a');
      tocJump.id = 'toc-jump';
      tocJump.href = '#toc';
      tocJump.innerHTML = tocJumpText;
      tocNav.appendChild(tocJump);
    }

    tocNav.appendChild(toggle);
  }

  var toc = document.getElementById('toc');
  if (toc) {
    createSidebarToggle();
    toggleSidebar(sidebarMedia.matches);

    /* If the sidebar has been manually opened and is currently overlaying the text
       (window too small for the MQ to add the margin to body),
       then auto-close the sidebar once you click on something in there. */
    toc.addEventListener('click', function(e) {
      if(e.target.tagName.toLowerCase() == "a" && document.body.classList.contains('toc-sidebar') && !sidebarMedia.matches) {
        toggleSidebar(false);
      }
    }, false);
  }
  else {
    console.warn("Cant find Table of Contents. Please use <nav id='toc'> around the ToC.");
  }

  /* Wrap tables in case they overflow */
  var tables = document.querySelectorAll(':not(.overlarge) > table.data, :not(.overlarge) > table.index');
  var numTables = tables.length;
  for (var i = 0; i < numTables; i++) {
    var table = tables[i];
    var wrapper = document.createElement('div');
    wrapper.className = 'overlarge';
    table.parentNode.insertBefore(wrapper, table);
    wrapper.appendChild(table);
  }

})();
</script>
</div>
</div>
</div>
</body>
</html>
