foreign-try.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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. <link rel="icon" href="../images/favicon.ico" type="image/ico"/>
  8. <body><div class="spirit-nav">
  9. <a accesskey="p" href="../recipes/asio-integration-1-70.html"><img src="../images/prev.png" alt="Prev"></a>
  10. <a accesskey="u" href="../recipes.html"><img src="../images/up.png" alt="Up"></a>
  11. <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">
  12. <div class="titlepage"><div><div><h1 style="clear: both">Extending <code>BOOST_OUTCOME_TRY</code></h1></div></div></div>
  13. <p>Outcome&rsquo;s <a href="../reference/macros/try.html" class="api-reference"><code>BOOST_OUTCOME_TRY(var, expr)</code></a>
  14. operation is fully extensible
  15. to accept as input any foreign types.
  16. It already recognises types matching the
  17. <a href="../reference/concepts/valueorerror.html" class="api-reference"><code>ValueOrError&lt;T, E&gt;</code></a>
  18. concept, which is to say all types which have:</p>
  19. <ul>
  20. <li>A public <code>.has_value()</code> member function which returns a <code>bool</code>.</li>
  21. <li>In order of preference, a public <code>.assume_value()</code>/<code>.value()</code> member
  22. function.</li>
  23. <li>In order of preference, a public <code>.as_failure()</code>/<code>.assume_error()</code>/<code>.error()</code>
  24. member function.</li>
  25. </ul>
  26. <p>This should automatically handle inputs of <code>std::expected&lt;T, E&gt;</code>, and many others,
  27. including intermixing Boost.Outcome and standalone Outcome within the same
  28. translation unit.</p>
  29. <p><code>BOOST_OUTCOME_TRY</code> has the following free function customisation points:</p>
  30. <dl>
  31. <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>
  32. <dd>Returns a `bool` which is true if the input to TRY has a value.
  33. <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>
  34. <dd>Returns a suitable <a href="../reference/types/failure_type.html" class="api-reference"><code>failure_type&lt;EC, EP = void&gt;</code></a>
  35. which
  36. is returned immediately to cause stack unwind. Ought to preserve rvalue
  37. semantics (i.e. if passed an rvalue, move the error state into the failure
  38. type).
  39. <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>
  40. <dd>Extracts a value type from the input for the `TRY` to set its variable.
  41. Ought to preserve rvalue semantics (i.e. if passed an rvalue, move the value).
  42. </dl>
  43. <p>New overloads of these to support additional input types must be injected into
  44. the <code>BOOST_OUTCOME_V2_NAMESPACE</code> namespace before the compiler parses the relevant
  45. <code>BOOST_OUTCOME_TRY</code> in order to be found. This is called &lsquo;early binding&rsquo; in the two
  46. phase name lookup model in C++. This was chosen over &lsquo;late binding&rsquo;, where an
  47. <code>BOOST_OUTCOME_TRY</code> in a templated piece of code could look up overloads introduced after
  48. parsing the template containing the <code>BOOST_OUTCOME_TRY</code>, because it has much lower
  49. impact on build times, as binding is done once at the point of parse, instead
  50. of on every occasion at the point of instantiation. If you are careful to ensure
  51. that you inject the overloads which you need early in the parse of the
  52. translation unit, all will be well.</p>
  53. <p>Let us work through an applied example.</p>
  54. <hr />
  55. <h2 id="a-very-foreign-pseudo-expected-type">A very foreign pseudo-Expected type</h2>
  56. <p>This is a paraphrase of a poorly written pseudo-Expected type which I once
  57. encountered in the production codebase of a large multinational. Lots
  58. of the code was already using it, and it was weird enough that it couldn&rsquo;t
  59. be swapped out for something better easily.</p>
  60. <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>
  61. <span class="p">{</span>
  62. <span class="n">kBadValue</span>
  63. <span class="p">};</span>
  64. <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>
  65. <span class="p">{</span>
  66. <span class="n">T</span> <span class="n">Value</span><span class="p">;</span>
  67. <span class="n">E</span> <span class="n">Error</span><span class="p">;</span>
  68. <span class="kt">int</span> <span class="n">IsErrored</span><span class="p">;</span>
  69. <span class="n">ForeignExpected</span><span class="p">(</span><span class="n">T</span> <span class="n">v</span><span class="p">)</span>
  70. <span class="o">:</span> <span class="n">Value</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
  71. <span class="p">,</span> <span class="n">Error</span><span class="p">()</span>
  72. <span class="p">,</span> <span class="n">IsErrored</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
  73. <span class="p">{</span>
  74. <span class="p">}</span>
  75. <span class="n">ForeignExpected</span><span class="p">(</span><span class="n">E</span> <span class="n">e</span><span class="p">)</span>
  76. <span class="o">:</span> <span class="n">Value</span><span class="p">()</span>
  77. <span class="p">,</span> <span class="n">Error</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
  78. <span class="p">,</span> <span class="n">IsErrored</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  79. <span class="p">{</span>
  80. <span class="p">}</span>
  81. <span class="p">};</span>
  82. </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>
  83. <p>What we would like is for new code to be written using Outcome, but be able
  84. to transparently call old code, like this:</p>
  85. <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
  86. </span><span class="c1"></span><span class="p">{</span>
  87. <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>
  88. <span class="k">return</span> <span class="n">kBadValue</span><span class="p">;</span>
  89. <span class="k">return</span> <span class="n">a</span><span class="p">;</span>
  90. <span class="p">}</span>
  91. <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
  92. </span><span class="c1"></span><span class="p">{</span>
  93. <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>
  94. <span class="k">return</span> <span class="n">x</span><span class="p">;</span>
  95. <span class="p">}</span>
  96. </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>
  97. <p>Telling Outcome about this weird foreign Expected is straightforward:</p>
  98. <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>
  99. <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">//
  100. </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>
  101. <span class="p">{</span>
  102. <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>
  103. <span class="p">}</span>
  104. <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">//
  105. </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>
  106. <span class="p">{</span>
  107. <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>
  108. <span class="p">{</span>
  109. <span class="k">case</span> <span class="nl">kBadValue</span><span class="p">:</span>
  110. <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>
  111. <span class="p">}</span>
  112. <span class="n">abort</span><span class="p">();</span>
  113. <span class="p">}</span>
  114. <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">//
  115. </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>
  116. <span class="p">{</span>
  117. <span class="k">return</span> <span class="n">v</span><span class="p">.</span><span class="n">Value</span><span class="p">;</span>
  118. <span class="p">}</span>
  119. <span class="n">BOOST_OUTCOME_V2_NAMESPACE_END</span>
  120. </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>
  121. <p>And now <code>BOOST_OUTCOME_TRY</code> works exactly as expected:</p>
  122. <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>
  123. <span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
  124. <span class="p">{</span>
  125. <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>
  126. <span class="p">}</span>
  127. <span class="k">else</span>
  128. <span class="p">{</span>
  129. <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>
  130. <span class="p">}</span>
  131. <span class="p">};</span>
  132. <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>
  133. <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>
  134. </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>
  135. <p>&hellip; which outputs:</p>
  136. <pre><code>new_code(5) returns successful 5
  137. new_code(0) returns failure argument out of domain
  138. </code></pre>
  139. </div><p><small>Last revised: June 22, 2019 at 21:22:42 &#43;0100</small></p>
  140. <hr>
  141. <div class="spirit-nav">
  142. <a accesskey="p" href="../recipes/asio-integration-1-70.html"><img src="../images/prev.png" alt="Prev"></a>
  143. <a accesskey="u" href="../recipes.html"><img src="../images/up.png" alt="Up"></a>
  144. <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>
  145. </html>