• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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&rsquo;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&lt;T, E&gt;</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&lt;T, E&gt;</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&lt;EC, EP = void&gt;</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 &lsquo;early binding&rsquo; in the two
57phase name lookup model in C++. This was chosen over &lsquo;late binding&rsquo;, 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&rsquo;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">&lt;</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">&gt;</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">&lt;</span><span class="kt">int</span><span class="o">&gt;</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">&lt;</span><span class="kt">int</span><span class="o">&gt;</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">&lt;</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">&gt;</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">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="o">&amp;</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">&lt;</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">&gt;</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">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="o">&amp;</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">&lt;</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">&gt;</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">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="o">&amp;</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">&lt;&lt;</span> <span class="n">desc</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; returns successful &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">x</span><span class="p">.</span><span class="n">value</span><span class="p">()</span> <span class="o">&lt;&lt;</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">&lt;&lt;</span> <span class="n">desc</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; returns failure &#34;</span> <span class="o">&lt;&lt;</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">&lt;&lt;</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">&#34;</span><span class="se">\n</span><span class="s">new_code(5)&#34;</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">&#34;</span><span class="se">\n</span><span class="s">new_code(0)&#34;</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>&hellip; 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 &#43;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