123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <title>ASIO/Networking TS: Boost >= 1.70 - Boost.Outcome documentation</title>
- <link rel="stylesheet" href="../css/boost.css" type="text/css">
- <meta name="generator" content="Hugo 0.52 with Boostdoc theme">
- <meta name="viewport" content="width=device-width,initial-scale=1.0"/>
- <link rel="icon" href="../images/favicon.ico" type="image/ico"/>
- <body><div class="spirit-nav">
- <a accesskey="p" href="../recipes/asio-integration.html"><img src="../images/prev.png" alt="Prev"></a>
- <a accesskey="u" href="../recipes.html"><img src="../images/up.png" alt="Up"></a>
- <a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../recipes/foreign-try.html"><img src="../images/next.png" alt="Next"></a></div><div id="content">
- <div class="titlepage"><div><div><h1 style="clear: both">ASIO/Networking TS: Boost >= 1.70</h1></div></div></div>
- <div class="toc"><dl class="toc">
- <dt>
- <dd><dl>
- <dt>
- <dd><dl>
- <dt><a href="#compatibility-note">Compatibility note</a></dt>
- <dt><a href="#use-case">Use case</a></dt>
- <dt><a href="#implementation">Implementation</a></dt>
- </dl></dd></dt>
- </dl></dd></dt>
- </dl>
- </div>
-
- <p><em>Thanks to <a href="https://github.com/cstratopoulos">Christos Stratopoulos</a> for this Outcome recipe.</em></p>
- <hr />
- <h3 id="compatibility-note">Compatibility note</h3>
- <p>This recipe targets Boost versions including and after 1.70, where coroutine support is
- based around the <code>asio::use_awaitable</code> completion token. For integration with Boost versions
- before 1.70, see <a href="asio-integration">this recipe</a>.</p>
- <hr />
- <h3 id="use-case">Use case</h3>
- <p><a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio.html">Boost.ASIO</a>
- and <a href="https://think-async.com/Asio/">standalone ASIO</a> provide the
- <a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/async_result.html"><code>async_result</code></a>
- customisation point for adapting arbitrary third party libraries, such as Outcome, into ASIO.</p>
- <p>Historically in ASIO you need to pass completion handler instances
- to the ASIO asynchronous i/o initiation functions. These get executed when the i/o
- completes.</p>
- <div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"> <span class="c1">// Dynamically allocate a buffer to read into. This must be move-only
- </span><span class="c1"></span> <span class="c1">// so it can be attached to the completion handler, hence the unique_ptr.
- </span><span class="c1"></span> <span class="k">auto</span> <span class="n">buffer</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="n">byte</span><span class="o">>></span><span class="p">(</span><span class="mi">1024</span><span class="p">);</span>
- <span class="c1">// Begin an asynchronous socket read, upon completion invoke
- </span><span class="c1"></span> <span class="c1">// the lambda function specified
- </span><span class="c1"></span> <span class="n">skt</span><span class="p">.</span><span class="n">async_read_some</span><span class="p">(</span><span class="n">asio</span><span class="o">::</span><span class="n">buffer</span><span class="p">(</span><span class="n">buffer</span><span class="o">-></span><span class="n">data</span><span class="p">(),</span> <span class="n">buffer</span><span class="o">-></span><span class="n">size</span><span class="p">()),</span>
- <span class="c1">// Retain lifetime of the i/o buffer until completion
- </span><span class="c1"></span> <span class="p">[</span><span class="n">buffer</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">buffer</span><span class="p">)](</span><span class="k">const</span> <span class="n">error_code</span> <span class="o">&</span><span class="n">ec</span><span class="p">,</span> <span class="n">size_t</span> <span class="n">bytes</span><span class="p">)</span> <span class="p">{</span>
- <span class="c1">// Handle the buffer read
- </span><span class="c1"></span> <span class="k">if</span><span class="p">(</span><span class="n">ec</span><span class="p">)</span>
- <span class="p">{</span>
- <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o"><<</span> <span class="s">"Buffer read failed with "</span> <span class="o"><<</span> <span class="n">ec</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
- <span class="k">return</span><span class="p">;</span>
- <span class="p">}</span>
- <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Read "</span> <span class="o"><<</span> <span class="n">bytes</span> <span class="o"><<</span> <span class="s">" bytes into buffer"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
- <span class="c1">// buffer will be dynamically freed now
- </span><span class="c1"></span> <span class="p">});</span>
- </code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/asio_integration_1_70.cpp#L48" class="code-snippet-url" target="_blank">View this code on Github</a></div>
- <p>One of the big value adds of the Coroutines TS is the ability to not have to write
- so much boilerplate if you have a Coroutines supporting compiler:</p>
- <div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"> <span class="c1">// As coroutines suspend the calling thread whilst an asynchronous
- </span><span class="c1"></span> <span class="c1">// operation executes, we can use stack allocation instead of dynamic
- </span><span class="c1"></span> <span class="c1">// allocation
- </span><span class="c1"></span> <span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">1024</span><span class="p">];</span>
- <span class="c1">// Asynchronously read data, suspending this coroutine until completion,
- </span><span class="c1"></span> <span class="c1">// returning the bytes of the data read into the result.
- </span><span class="c1"></span> <span class="k">try</span>
- <span class="p">{</span>
- <span class="c1">// The use_awaitable completion token represents the current coroutine
- </span><span class="c1"></span> <span class="c1">// (requires Coroutines TS)
- </span><span class="c1"></span> <span class="n">size_t</span> <span class="n">bytesread</span> <span class="o">=</span> <span class="c1">//
- </span><span class="c1"></span> <span class="n">co_await</span> <span class="n">skt</span><span class="p">.</span><span class="n">async_read_some</span><span class="p">(</span><span class="n">asio</span><span class="o">::</span><span class="n">buffer</span><span class="p">(</span><span class="n">buffer</span><span class="p">),</span> <span class="n">asio</span><span class="o">::</span><span class="n">use_awaitable</span><span class="p">);</span>
- <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Read "</span> <span class="o"><<</span> <span class="n">bytesread</span> <span class="o"><<</span> <span class="s">" bytes into buffer"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
- <span class="p">}</span>
- <span class="k">catch</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">system_error</span> <span class="o">&</span><span class="n">e</span><span class="p">)</span>
- <span class="p">{</span>
- <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o"><<</span> <span class="s">"Buffer read failed with "</span> <span class="o"><<</span> <span class="n">e</span><span class="p">.</span><span class="n">what</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>
- <span class="p">}</span>
- </code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/asio_integration_1_70.cpp#L74" class="code-snippet-url" target="_blank">View this code on Github</a></div>
- <p>The default ASIO implementation always throws exceptions on failure through
- its coroutine token transformation. The <a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/experimental__redirect_error.html"><code>redirect_error</code></a>
- token transformation recovers the option to use the <code>error_code</code> interface,
- but it suffers from the <a href="../motivation/error_codes.html">same drawbacks</a>
- that make pure error codes unappealing in the synchronous case.</p>
- <p>This recipe fixes that by making it possible for coroutinised
- i/o in ASIO to return a <code>result<T></code>:</p>
- <div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"> <span class="c1">// Asynchronously read data, suspending this coroutine until completion,
- </span><span class="c1"></span> <span class="c1">// returning the bytes of the data read into the result, or any failure.
- </span><span class="c1"></span> <span class="n">outcome</span><span class="o">::</span><span class="n">result</span><span class="o"><</span><span class="n">size_t</span><span class="p">,</span> <span class="n">error_code</span><span class="o">></span> <span class="n">bytesread</span> <span class="o">=</span> <span class="c1">//
- </span><span class="c1"></span> <span class="n">co_await</span> <span class="n">skt</span><span class="p">.</span><span class="n">async_read_some</span><span class="p">(</span><span class="n">asio</span><span class="o">::</span><span class="n">buffer</span><span class="p">(</span><span class="n">buffer</span><span class="p">),</span> <span class="n">as_result</span><span class="p">(</span><span class="n">asio</span><span class="o">::</span><span class="n">use_awaitable</span><span class="p">));</span>
- <span class="c1">// Usage is exactly like ordinary Outcome. Note the lack of exception throw!
- </span><span class="c1"></span> <span class="k">if</span><span class="p">(</span><span class="n">bytesread</span><span class="p">.</span><span class="n">has_error</span><span class="p">())</span>
- <span class="p">{</span>
- <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o"><<</span> <span class="s">"Buffer read failed with "</span> <span class="o"><<</span> <span class="n">bytesread</span><span class="p">.</span><span class="n">error</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>
- <span class="k">return</span><span class="p">;</span>
- <span class="p">}</span>
- <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Read "</span> <span class="o"><<</span> <span class="n">bytesread</span><span class="p">.</span><span class="n">value</span><span class="p">()</span> <span class="o"><<</span> <span class="s">" bytes into buffer"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
- </code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/asio_integration_1_70.cpp#L208" class="code-snippet-url" target="_blank">View this code on Github</a></div>
- <hr />
- <h3 id="implementation">Implementation</h3>
- <div class="notices warning" style="background: url('../images/warning.png') top left no-repeat padding-box padding-box;">
- <div class="notices heading">warning</div>
- <div class="notices message"><p>The below involves a lot of ASIO voodoo. <strong>NO SUPPORT WILL BE GIVEN HERE FOR THE ASIO
- CODE BELOW</strong>. Please raise any questions or problems that you have with how to implement
- this sort of stuff in ASIO
- on <a href="https://stackoverflow.com/questions/tagged/boost-asio">Stackoverflow #boost-asio</a>.</p>
- </div>
- </div>
- <p>The real world, production-level recipe can be found at the bottom of this page.
- You ought to use that in any real world use case.</p>
- <p>It is however worth providing a walkthrough of a simplified edition of the real world
- recipe, as a lot of barely documented ASIO voodoo is involved. You should not
- use the code presented next in your own code, it is too simplified. But it should
- help you understand how the real implementation works.</p>
- <p>Firstly we need to define some helper type sugar and a factory function for wrapping
- any arbitrary third party completion token with that type sugar:</p>
- <div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="k">namespace</span> <span class="n">detail</span>
- <span class="p">{</span>
- <span class="c1">// Type sugar for wrapping an external completion token
- </span><span class="c1"></span> <span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">CompletionToken</span><span class="o">></span> <span class="k">struct</span> <span class="n">as_result_t</span>
- <span class="p">{</span>
- <span class="n">CompletionToken</span> <span class="n">token</span><span class="p">;</span>
- <span class="p">};</span>
- <span class="p">}</span> <span class="c1">// namespace detail
- </span><span class="c1"></span>
- <span class="c1">// Factory function for wrapping a third party completion token with
- </span><span class="c1">// our type sugar
- </span><span class="c1"></span><span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">CompletionToken</span><span class="o">></span> <span class="c1">//
- </span><span class="c1"></span><span class="kr">inline</span> <span class="k">auto</span> <span class="n">as_result</span><span class="p">(</span><span class="n">CompletionToken</span> <span class="o">&&</span><span class="n">token</span><span class="p">)</span>
- <span class="p">{</span>
- <span class="k">return</span> <span class="n">detail</span><span class="o">::</span><span class="n">as_result_t</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="n">CompletionToken</span><span class="o">>></span><span class="p">{</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o"><</span><span class="n">CompletionToken</span><span class="o">></span><span class="p">(</span><span class="n">token</span><span class="p">)};</span>
- <span class="p">};</span>
- </code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/asio_integration_1_70.cpp#L97" class="code-snippet-url" target="_blank">View this code on Github</a></div>
- <p>Next we tell ASIO about a new completion token it ought to recognise by specialising
- <a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/async_result.html"><code>async_result</code></a>:</p>
- <div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="c1">// Tell ASIO about a new kind of completion token, the kind returned
- </span><span class="c1">// from our as_result() factory function. This implementation is
- </span><span class="c1">// for functions with handlers void(error_code, T) only.
- </span><span class="c1"></span><span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">CompletionToken</span><span class="p">,</span> <span class="k">class</span><span class="err"> </span><span class="nc">T</span><span class="o">></span> <span class="c1">//
- </span><span class="c1"></span><span class="k">struct</span> <span class="n">asio</span><span class="o">::</span><span class="n">async_result</span><span class="o"><</span><span class="n">detail</span><span class="o">::</span><span class="n">as_result_t</span><span class="o"><</span><span class="n">CompletionToken</span><span class="o">></span><span class="p">,</span> <span class="c1">//
- </span><span class="c1"></span> <span class="kt">void</span><span class="p">(</span><span class="n">error_code</span><span class="p">,</span> <span class="n">T</span><span class="p">)</span><span class="o">></span> <span class="c1">//
- </span><span class="c1"></span>
- <span class="p">{</span>
- <span class="c1">// The result type we shall return
- </span><span class="c1"></span> <span class="k">using</span> <span class="n">result_type</span> <span class="o">=</span> <span class="n">outcome</span><span class="o">::</span><span class="n">result</span><span class="o"><</span><span class="n">T</span><span class="p">,</span> <span class="n">error_code</span><span class="o">></span><span class="p">;</span>
- <span class="c1">// The awaitable type to be returned by the initiating function,
- </span><span class="c1"></span> <span class="c1">// the co_await of which will yield a result_type
- </span><span class="c1"></span> <span class="k">using</span> <span class="n">return_type</span> <span class="o">=</span> <span class="c1">//
- </span><span class="c1"></span> <span class="k">typename</span> <span class="n">asio</span><span class="o">::</span><span class="n">async_result</span><span class="o"><</span><span class="n">CompletionToken</span><span class="p">,</span> <span class="kt">void</span><span class="p">(</span><span class="n">result_type</span><span class="p">)</span><span class="o">></span> <span class="c1">//
- </span><span class="c1"></span> <span class="o">::</span><span class="n">return_type</span><span class="p">;</span>
- </code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/asio_integration_1_70.cpp#L116" class="code-snippet-url" target="_blank">View this code on Github</a></div>
- <p>There are a couple tricky parts to understand. First of all, we want our
- <code>async_result</code> specialization to work, in particular, with the <code>async_result</code> for
- ASIO’s
- <a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/use_awaitable_t.html"><code>use_awaitable_t</code> completion token</a>.
- With this token, the <code>async_result</code> specialization takes the form with a static
- <code>initiate</code> method which defers initiation of the asynchronous operation until,
- for example,
- <code>co_await</code> is called on the returned <code>awaitable</code>. Thus, our <code>async_result</code>
- specialization will take the same form. With this in mind, we need only
- understand how our specialization will implement its <code>initiate</code> method. The trick
- is that it will pass the initiation work off to an <code>async_result</code> for the
- supplied completion token type with a completion handler which consumes <code>result<T></code>.
- Our <code>async_result</code> is thus just a simple wrapper over this underlying
- <code>async_result</code>, but we inject a completion handler with the
- <code>void(error_code, size_t)</code> signature which constructs from that a <code>result</code>:</p>
- <div class="code-snippet"><div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"> <span class="c1">// Wrap a completion handler with void(error_code, T) converting
- </span><span class="c1"></span> <span class="c1">// handler
- </span><span class="c1"></span> <span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">Handler</span><span class="o">></span>
- <span class="k">struct</span> <span class="n">completion_handler</span> <span class="p">{</span>
- <span class="c1">// Our completion handler spec
- </span><span class="c1"></span> <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="n">error_code</span> <span class="n">ec</span><span class="p">,</span> <span class="n">T</span> <span class="n">v</span><span class="p">)</span>
- <span class="p">{</span>
- <span class="c1">// Call the underlying completion handler, whose
- </span><span class="c1"></span> <span class="c1">// completion function is void(result_type)
- </span><span class="c1"></span> <span class="k">if</span><span class="p">(</span><span class="n">ec</span><span class="p">)</span>
- <span class="p">{</span>
- <span class="c1">// Complete with a failed result
- </span><span class="c1"></span> <span class="n">_handler</span><span class="p">(</span><span class="n">result_type</span><span class="p">(</span><span class="n">outcome</span><span class="o">::</span><span class="n">failure</span><span class="p">(</span><span class="n">ec</span><span class="p">)));</span>
- <span class="k">return</span><span class="p">;</span>
- <span class="p">}</span>
- <span class="c1">// Complete with a successful result
- </span><span class="c1"></span> <span class="n">_handler</span><span class="p">(</span><span class="n">result_type</span><span class="p">(</span><span class="n">outcome</span><span class="o">::</span><span class="n">success</span><span class="p">(</span><span class="n">v</span><span class="p">)));</span>
- <span class="p">}</span>
- <span class="n">Handler</span> <span class="n">_handler</span><span class="p">;</span>
- <span class="p">};</span>
- <span class="c1">// NOTE the initiate member function initiates the async operation,
- </span><span class="c1"></span> <span class="c1">// and we want to defer to what would be the initiation of the
- </span><span class="c1"></span> <span class="c1">// async_result whose handler signature is void(result_type).
- </span><span class="c1"></span> <span class="k">template</span> <span class="o"><</span><span class="k">class</span><span class="err"> </span><span class="nc">Initiation</span><span class="p">,</span> <span class="k">class</span><span class="err">... </span><span class="nc">Args</span><span class="o">></span>
- <span class="k">static</span> <span class="n">return_type</span>
- <span class="n">initiate</span><span class="p">(</span>
- <span class="n">Initiation</span><span class="o">&&</span> <span class="n">init</span><span class="p">,</span>
- <span class="n">detail</span><span class="o">::</span><span class="n">as_result_t</span><span class="o"><</span><span class="n">CompletionToken</span><span class="o">>&&</span> <span class="n">token</span><span class="p">,</span>
- <span class="n">Args</span><span class="o">&&</span><span class="p">...</span> <span class="n">args</span><span class="p">)</span>
- <span class="p">{</span>
- <span class="c1">// The async_initiate<CompletionToken, void(result_type)> helper
- </span><span class="c1"></span> <span class="c1">// function will invoke the async initiation method of the
- </span><span class="c1"></span> <span class="c1">// async_result<CompletionToken, void(result_type)>, as desired.
- </span><span class="c1"></span> <span class="c1">// Instead of CompletionToken and void(result_type) we start with
- </span><span class="c1"></span> <span class="c1">// detail::as_result_t<CompletionToken> and void(ec, T), so
- </span><span class="c1"></span> <span class="c1">// the inputs need to be massaged then passed along.
- </span><span class="c1"></span> <span class="k">return</span> <span class="n">asio</span><span class="o">::</span><span class="n">async_initiate</span><span class="o"><</span><span class="n">CompletionToken</span><span class="p">,</span> <span class="kt">void</span><span class="p">(</span><span class="n">result_type</span><span class="p">)</span><span class="o">></span><span class="p">(</span>
- <span class="c1">// create a new initiation which wraps the provided init
- </span><span class="c1"></span> <span class="p">[</span><span class="n">init</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o"><</span><span class="n">Initiation</span><span class="o">></span><span class="p">(</span><span class="n">init</span><span class="p">)](</span>
- <span class="k">auto</span><span class="o">&&</span> <span class="n">handler</span><span class="p">,</span> <span class="k">auto</span><span class="o">&&</span><span class="p">...</span> <span class="n">initArgs</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
- <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">init</span><span class="p">)(</span>
- <span class="c1">// we wrap the handler in the converting completion_handler from
- </span><span class="c1"></span> <span class="c1">// above, and pass along the args
- </span><span class="c1"></span> <span class="n">completion_handler</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">handler</span><span class="p">)</span><span class="o">>></span><span class="p">{</span>
- <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">handler</span><span class="p">)</span><span class="o">></span><span class="p">(</span><span class="n">handler</span><span class="p">)},</span>
- <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o"><</span><span class="k">decltype</span><span class="p">(</span><span class="n">initArgs</span><span class="p">)</span><span class="o">></span><span class="p">(</span><span class="n">initArgs</span><span class="p">)...);</span>
- <span class="p">},</span>
- <span class="c1">// the new initiation is called with the handler unwrapped from
- </span><span class="c1"></span> <span class="c1">// the token, and the original initiation arguments.
- </span><span class="c1"></span> <span class="n">token</span><span class="p">.</span><span class="n">token</span><span class="p">,</span>
- <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o"><</span><span class="n">Args</span><span class="o">></span><span class="p">(</span><span class="n">args</span><span class="p">)...);</span>
- <span class="p">}</span>
- <span class="p">};</span>
- </code></pre></div><a href="https://github.com/boostorg/outcome/tree/master/doc/src/snippets/boost-only/asio_integration_1_70.cpp#L134" class="code-snippet-url" target="_blank">View this code on Github</a></div>
- <p>To use, simply wrap the third party completion token with <code>as_result</code> to cause
- ASIO to return from <code>co_await</code> a <code>result</code> instead of throwing exceptions on
- failure:</p>
- <div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">1024</span><span class="p">];</span>
- <span class="n">outcome</span><span class="o">::</span><span class="n">result</span><span class="o"><</span><span class="n">size_t</span><span class="p">,</span> <span class="n">error_code</span><span class="o">></span> <span class="n">bytesread</span> <span class="o">=</span>
- <span class="n">co_await</span> <span class="n">skt</span><span class="p">.</span><span class="n">async_read_some</span><span class="p">(</span><span class="n">asio</span><span class="o">::</span><span class="n">buffer</span><span class="p">(</span><span class="n">buffer</span><span class="p">),</span> <span class="n">as_result</span><span class="p">(</span><span class="n">asio</span><span class="o">::</span><span class="n">use_awaitable</span><span class="p">));</span>
- </code></pre></div>
- <p>The real world production-level implementation below is a lot more complex than the
- above which has been deliberately simplified to aid exposition. The above
- should help you get up and running with the below, eventually.</p>
- <p>One again I would like to remind you that Outcome is not the appropriate place
- to seek help with ASIO voodoo. Please ask on
- <a href="https://stackoverflow.com/questions/tagged/boost-asio">Stackoverflow #boost-asio</a>.</p>
- <hr />
- <p>Here follows the real world, production-level adapation of Outcome into
- ASIO, written and maintained by <a href="https://github.com/cstratopoulos">Christos Stratopoulos</a>.
- If the following does not load due to Javascript being disabled, you can visit the gist at
- <a href="https://gist.github.com/cstratopoulos/901b5cdd41d07c6ce6d83798b09ecf9b/863c1dbf3b063a5ff9ff2bdd834242ead556e74e">https://gist.github.com/cstratopoulos/901b5cdd41d07c6ce6d83798b09ecf9b/863c1dbf3b063a5ff9ff2bdd834242ead556e74e</a>.</p>
- <script type="application/javascript" src="//gist.github.com/cstratopoulos/901b5cdd41d07c6ce6d83798b09ecf9b/863c1dbf3b063a5ff9ff2bdd834242ead556e74e.js"></script>
- </div><p><small>Last revised: August 06, 2019 at 10:42:06 +0100</small></p>
- <hr>
- <div class="spirit-nav">
- <a accesskey="p" href="../recipes/asio-integration.html"><img src="../images/prev.png" alt="Prev"></a>
- <a accesskey="u" href="../recipes.html"><img src="../images/up.png" alt="Up"></a>
- <a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../recipes/foreign-try.html"><img src="../images/next.png" alt="Next"></a></div></body>
- </html>
|