1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 2<html><meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 3<title>Extending BOOST_OUTCOME_TRY - Boost.Outcome documentation</title> 4<link rel="stylesheet" href="../css/boost.css" type="text/css"> 5<meta name="generator" content="Hugo 0.52 with Boostdoc theme"> 6<meta name="viewport" content="width=device-width,initial-scale=1.0"/> 7 8<link rel="icon" href="../images/favicon.ico" type="image/ico"/> 9<body><div class="spirit-nav"> 10<a accesskey="p" href="../recipes/asio-integration-1-70.html"><img src="../images/prev.png" alt="Prev"></a> 11 <a accesskey="u" href="../recipes.html"><img src="../images/up.png" alt="Up"></a> 12 <a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../experimental.html"><img src="../images/next.png" alt="Next"></a></div><div id="content"> 13 <div class="titlepage"><div><div><h1 style="clear: both">Extending <code>BOOST_OUTCOME_TRY</code></h1></div></div></div> 14 15 16<p>Outcome’s <a href="../reference/macros/try.html" class="api-reference"><code>BOOST_OUTCOME_TRY(var, expr)</code></a> 17 operation is fully extensible 18to accept as input any foreign types. 19It already recognises types matching the 20<a href="../reference/types/basic_result/explicit_valueorerror_converting_constructor.html" class="api-reference"><code>ValueOrError<T, E></code></a> 21 concept, which is to say all types which have:</p> 22 23<ul> 24<li>A public <code>.has_value()</code> member function which returns a <code>bool</code>.</li> 25<li>In order of preference, a public <code>.assume_value()</code>/<code>.value()</code> member 26function.</li> 27<li>In order of preference, a public <code>.as_failure()</code>/<code>.assume_error()</code>/<code>.error()</code> 28member function.</li> 29</ul> 30 31<p>This should automatically handle inputs of <code>std::expected<T, E></code>, and many others, 32including intermixing Boost.Outcome and standalone Outcome within the same 33translation unit.</p> 34 35<p><code>BOOST_OUTCOME_TRY</code> has the following free function customisation points:</p> 36 37<dl> 38<dt><code>BOOST_OUTCOME_V2_NAMESPACE::</code><a href="../reference/functions/try_operation_has_value.html" class="api-reference"><code>try_operation_has_value(X)</code></a> 39 40<dd>Returns a `bool` which is true if the input to TRY has a value. 41<dt><code>BOOST_OUTCOME_V2_NAMESPACE::</code><a href="../reference/functions/try_operation_return_as.html" class="api-reference"><code>try_operation_return_as(X)</code></a> 42 43<dd>Returns a suitable <a href="../reference/types/failure_type.html" class="api-reference"><code>failure_type<EC, EP = void></code></a> 44 which 45is returned immediately to cause stack unwind. Ought to preserve rvalue 46semantics (i.e. if passed an rvalue, move the error state into the failure 47type). 48<dt><code>BOOST_OUTCOME_V2_NAMESPACE::</code><a href="../reference/functions/try_operation_extract_value.html" class="api-reference"><code>try_operation_extract_value(X)</code></a> 49 50<dd>Extracts a value type from the input for the `TRY` to set its variable. 51Ought to preserve rvalue semantics (i.e. if passed an rvalue, move the value). 52</dl> 53 54<p>New overloads of these to support additional input types must be injected into 55the <code>BOOST_OUTCOME_V2_NAMESPACE</code> namespace before the compiler parses the relevant 56<code>BOOST_OUTCOME_TRY</code> in order to be found. This is called ‘early binding’ in the two 57phase name lookup model in C++. This was chosen over ‘late binding’, where an 58<code>BOOST_OUTCOME_TRY</code> in a templated piece of code could look up overloads introduced after 59parsing the template containing the <code>BOOST_OUTCOME_TRY</code>, because it has much lower 60impact on build times, as binding is done once at the point of parse, instead 61of on every occasion at the point of instantiation. If you are careful to ensure 62that you inject the overloads which you need early in the parse of the 63translation unit, all will be well.</p> 64 65<p>Let us work through an applied example.</p> 66 67<hr /> 68 69<h2 id="a-very-foreign-pseudo-expected-type">A very foreign pseudo-Expected type</h2> 70 71<p>This is a paraphrase of a poorly written pseudo-Expected type which I once 72encountered in the production codebase of a large multinational. Lots 73of the code was already using it, and it was weird enough that it couldn’t 74be swapped out for something better easily.</p> 75 76<div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="k">enum</span> <span class="n">Errc</span> 77<span class="p">{</span> 78 <span class="n">kBadValue</span> 79<span class="p">};</span> 80<span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">T</span><span class="p">,</span> <span class="k">class</span><span class="err"> </span><span class="nc">E</span> <span class="o">=</span> <span class="n">Errc</span><span class="o">></span> <span class="k">struct</span> <span class="n">ForeignExpected</span> 81<span class="p">{</span> 82 <span class="n">T</span> <span class="n">Value</span><span class="p">;</span> 83 <span class="n">E</span> <span class="n">Error</span><span class="p">;</span> 84 <span class="kt">int</span> <span class="n">IsErrored</span><span class="p">;</span> 85 86 <span class="n">ForeignExpected</span><span class="p">(</span><span class="n">T</span> <span class="n">v</span><span class="p">)</span> 87 <span class="o">:</span> <span class="n">Value</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> 88 <span class="p">,</span> <span class="n">Error</span><span class="p">()</span> 89 <span class="p">,</span> <span class="n">IsErrored</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> 90 <span class="p">{</span> 91 <span class="p">}</span> 92 <span class="n">ForeignExpected</span><span class="p">(</span><span class="n">E</span> <span class="n">e</span><span class="p">)</span> 93 <span class="o">:</span> <span class="n">Value</span><span class="p">()</span> 94 <span class="p">,</span> <span class="n">Error</span><span class="p">(</span><span class="n">e</span><span class="p">)</span> 95 <span class="p">,</span> <span class="n">IsErrored</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> 96 <span class="p">{</span> 97 <span class="p">}</span> 98<span class="p">};</span> 99</code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/foreign_try.cpp#L37" class="code-snippet-url" target="_blank">View this code on Github</a></div> 100 101 102<p>What we would like is for new code to be written using Outcome, but be able 103to transparently call old code, like this:</p> 104 105<div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="n">ForeignExpected</span><span class="o"><</span><span class="kt">int</span><span class="o">></span> <span class="n">old_code</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">)</span> <span class="c1">// old code 106</span><span class="c1"></span><span class="p">{</span> 107 <span class="k">if</span><span class="p">(</span><span class="mi">0</span> <span class="o">==</span> <span class="n">a</span><span class="p">)</span> 108 <span class="k">return</span> <span class="n">kBadValue</span><span class="p">;</span> 109 <span class="k">return</span> <span class="n">a</span><span class="p">;</span> 110<span class="p">}</span> 111 112<span class="n">outcome</span><span class="o">::</span><span class="n">result</span><span class="o"><</span><span class="kt">int</span><span class="o">></span> <span class="n">new_code</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">)</span> <span class="c1">// new code 113</span><span class="c1"></span><span class="p">{</span> 114 <span class="n">BOOST_OUTCOME_TRY</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">old_code</span><span class="p">(</span><span class="n">a</span><span class="p">));</span> 115 <span class="k">return</span> <span class="n">x</span><span class="p">;</span> 116<span class="p">}</span> 117</code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/foreign_try.cpp#L88" class="code-snippet-url" target="_blank">View this code on Github</a></div> 118 119 120<p>Telling Outcome about this weird foreign Expected is straightforward:</p> 121 122<div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="n">BOOST_OUTCOME_V2_NAMESPACE_BEGIN</span> 123<span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">T</span><span class="p">,</span> <span class="k">class</span><span class="err"> </span><span class="nc">E</span><span class="o">></span> <span class="c1">// 124</span><span class="c1"></span><span class="kr">inline</span> <span class="kt">bool</span> <span class="n">try_operation_has_value</span><span class="p">(</span><span class="k">const</span> <span class="n">ForeignExpected</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">></span> <span class="o">&</span><span class="n">v</span><span class="p">)</span> 125<span class="p">{</span> 126 <span class="k">return</span> <span class="mi">0</span> <span class="o">==</span> <span class="n">v</span><span class="p">.</span><span class="n">IsErrored</span><span class="p">;</span> 127<span class="p">}</span> 128<span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">T</span><span class="p">,</span> <span class="k">class</span><span class="err"> </span><span class="nc">E</span><span class="o">></span> <span class="c1">// 129</span><span class="c1"></span><span class="kr">inline</span> <span class="k">auto</span> <span class="n">try_operation_return_as</span><span class="p">(</span><span class="k">const</span> <span class="n">ForeignExpected</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">></span> <span class="o">&</span><span class="n">v</span><span class="p">)</span> 130<span class="p">{</span> 131 <span class="k">switch</span><span class="p">(</span><span class="n">v</span><span class="p">.</span><span class="n">Error</span><span class="p">)</span> 132 <span class="p">{</span> 133 <span class="k">case</span> <span class="nl">kBadValue</span><span class="p">:</span> 134 <span class="k">return</span> <span class="n">failure</span><span class="p">(</span><span class="n">make_error_code</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">errc</span><span class="o">::</span><span class="n">argument_out_of_domain</span><span class="p">));</span> 135 <span class="p">}</span> 136 <span class="n">abort</span><span class="p">();</span> 137<span class="p">}</span> 138<span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">T</span><span class="p">,</span> <span class="k">class</span><span class="err"> </span><span class="nc">E</span><span class="o">></span> <span class="c1">// 139</span><span class="c1"></span><span class="kr">inline</span> <span class="k">auto</span> <span class="n">try_operation_extract_value</span><span class="p">(</span><span class="k">const</span> <span class="n">ForeignExpected</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">></span> <span class="o">&</span><span class="n">v</span><span class="p">)</span> 140<span class="p">{</span> 141 <span class="k">return</span> <span class="n">v</span><span class="p">.</span><span class="n">Value</span><span class="p">;</span> 142<span class="p">}</span> 143<span class="n">BOOST_OUTCOME_V2_NAMESPACE_END</span> 144</code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/foreign_try.cpp#L63" class="code-snippet-url" target="_blank">View this code on Github</a></div> 145 146 147<p>And now <code>BOOST_OUTCOME_TRY</code> works exactly as expected:</p> 148 149<div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"> <span class="k">auto</span> <span class="n">printresult</span> <span class="o">=</span> <span class="p">[](</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">desc</span><span class="p">,</span> <span class="k">auto</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> 150 <span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> 151 <span class="p">{</span> 152 <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">desc</span> <span class="o"><<</span> <span class="s">" returns successful "</span> <span class="o"><<</span> <span class="n">x</span><span class="p">.</span><span class="n">value</span><span class="p">()</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> 153 <span class="p">}</span> 154 <span class="k">else</span> 155 <span class="p">{</span> 156 <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">desc</span> <span class="o"><<</span> <span class="s">" returns failure "</span> <span class="o"><<</span> <span class="n">x</span><span class="p">.</span><span class="n">error</span><span class="p">().</span><span class="n">message</span><span class="p">()</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> 157 <span class="p">}</span> 158 <span class="p">};</span> 159 <span class="n">printresult</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">new_code(5)"</span><span class="p">,</span> <span class="n">new_code</span><span class="p">(</span><span class="mi">5</span><span class="p">));</span> 160 <span class="n">printresult</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">new_code(0)"</span><span class="p">,</span> <span class="n">new_code</span><span class="p">(</span><span class="mi">0</span><span class="p">));</span> 161</code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/foreign_try.cpp#L105" class="code-snippet-url" target="_blank">View this code on Github</a></div> 162 163 164<p>… which outputs:</p> 165 166<pre><code>new_code(5) returns successful 5 167 168new_code(0) returns failure argument out of domain 169</code></pre> 170 171 172 </div><p><small>Last revised: June 22, 2019 at 21:22:42 +0100</small></p> 173<hr> 174<div class="spirit-nav"> 175<a accesskey="p" href="../recipes/asio-integration-1-70.html"><img src="../images/prev.png" alt="Prev"></a> 176 <a accesskey="u" href="../recipes.html"><img src="../images/up.png" alt="Up"></a> 177 <a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../experimental.html"><img src="../images/next.png" alt="Next"></a></div></body> 178</html> 179