• 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>ASIO/Networking TS: Boost &gt;= 1.70 - 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.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="../recipes/foreign-try.html"><img src="../images/next.png" alt="Next"></a></div><div id="content">
13  <div class="titlepage"><div><div><h1 style="clear: both">ASIO/Networking TS: Boost &gt;= 1.70</h1></div></div></div>
14  <div class="toc"><dl class="toc">
15<dt>
16<dd><dl>
17<dt>
18<dd><dl>
19<dt><a href="#compatibility-note">Compatibility note</a></dt>
20<dt><a href="#use-case">Use case</a></dt>
21<dt><a href="#implementation">Implementation</a></dt>
22</dl></dd></dt>
23</dl></dd></dt>
24</dl>
25  </div>
26
27
28<p><em>Thanks to <a href="https://github.com/cstratopoulos">Christos Stratopoulos</a> for this Outcome recipe.</em></p>
29
30<hr />
31
32<h3 id="compatibility-note">Compatibility note</h3>
33
34<p>This recipe targets Boost versions including and after 1.70, where coroutine support is
35based around the <code>asio::use_awaitable</code> completion token. For integration with Boost versions
36before 1.70, see <a href="asio-integration">this recipe</a>.</p>
37
38<hr />
39
40<h3 id="use-case">Use case</h3>
41
42<p><a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio.html">Boost.ASIO</a>
43and <a href="https://think-async.com/Asio/">standalone ASIO</a> provide the
44<a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/async_result.html"><code>async_result</code></a>
45customisation point for adapting arbitrary third party libraries, such as Outcome, into ASIO.</p>
46
47<p>Historically in ASIO you need to pass completion handler instances
48to the ASIO asynchronous i/o initiation functions. These get executed when the i/o
49completes.</p>
50
51<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
52</span><span class="c1"></span>  <span class="c1">// so it can be attached to the completion handler, hence the unique_ptr.
53</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">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">byte</span><span class="o">&gt;&gt;</span><span class="p">(</span><span class="mi">1024</span><span class="p">);</span>
54
55  <span class="c1">// Begin an asynchronous socket read, upon completion invoke
56</span><span class="c1"></span>  <span class="c1">// the lambda function specified
57</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">-&gt;</span><span class="n">data</span><span class="p">(),</span> <span class="n">buffer</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">()),</span>
58
59                      <span class="c1">// Retain lifetime of the i/o buffer until completion
60</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">&amp;</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>
61                        <span class="c1">// Handle the buffer read
62</span><span class="c1"></span>                        <span class="k">if</span><span class="p">(</span><span class="n">ec</span><span class="p">)</span>
63                        <span class="p">{</span>
64                          <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Buffer read failed with &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">ec</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>
65                          <span class="k">return</span><span class="p">;</span>
66                        <span class="p">}</span>
67                        <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Read &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">bytes</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; bytes into buffer&#34;</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>
68
69                        <span class="c1">// buffer will be dynamically freed now
70</span><span class="c1"></span>                      <span class="p">});</span>
71</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>
72
73
74<p>One of the big value adds of the Coroutines TS is the ability to not have to write
75so much boilerplate if you have a Coroutines supporting compiler:</p>
76
77<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
78</span><span class="c1"></span>  <span class="c1">// operation executes, we can use stack allocation instead of dynamic
79</span><span class="c1"></span>  <span class="c1">// allocation
80</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>
81
82  <span class="c1">// Asynchronously read data, suspending this coroutine until completion,
83</span><span class="c1"></span>  <span class="c1">// returning the bytes of the data read into the result.
84</span><span class="c1"></span>  <span class="k">try</span>
85  <span class="p">{</span>
86    <span class="c1">// The use_awaitable completion token represents the current coroutine
87</span><span class="c1"></span>    <span class="c1">// (requires Coroutines TS)
88</span><span class="c1"></span>    <span class="n">size_t</span> <span class="n">bytesread</span> <span class="o">=</span>  <span class="c1">//
89</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>
90    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Read &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">bytesread</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; bytes into buffer&#34;</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>
91  <span class="p">}</span>
92  <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">&amp;</span><span class="n">e</span><span class="p">)</span>
93  <span class="p">{</span>
94    <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Buffer read failed with &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">e</span><span class="p">.</span><span class="n">what</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>
95  <span class="p">}</span>
96</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>
97
98
99<p>The default ASIO implementation always throws exceptions on failure through
100its 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>
101token transformation recovers the option to use the <code>error_code</code> interface,
102but it suffers from the <a href="../motivation/error_codes.html">same drawbacks</a>
103that make pure error codes unappealing in the synchronous case.</p>
104
105<p>This recipe fixes that by making it possible for coroutinised
106i/o in ASIO to return a <code>result&lt;T&gt;</code>:</p>
107
108<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,
109</span><span class="c1"></span>  <span class="c1">// returning the bytes of the data read into the result, or any failure.
110</span><span class="c1"></span>  <span class="n">outcome</span><span class="o">::</span><span class="n">result</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="n">error_code</span><span class="o">&gt;</span> <span class="n">bytesread</span> <span class="o">=</span>  <span class="c1">//
111</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>
112
113  <span class="c1">// Usage is exactly like ordinary Outcome. Note the lack of exception throw!
114</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>
115  <span class="p">{</span>
116    <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Buffer read failed with &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">bytesread</span><span class="p">.</span><span class="n">error</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>
117    <span class="k">return</span><span class="p">;</span>
118  <span class="p">}</span>
119  <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&#34;Read &#34;</span> <span class="o">&lt;&lt;</span> <span class="n">bytesread</span><span class="p">.</span><span class="n">value</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="s">&#34; bytes into buffer&#34;</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>
120</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>
121
122
123<hr />
124
125<h3 id="implementation">Implementation</h3>
126
127<div class="notices warning" style="background: url('../images/warning.png') top left no-repeat padding-box padding-box;">
128<div class="notices heading">warning</div>
129<div class="notices message"><p>The below involves a lot of ASIO voodoo. <strong>NO SUPPORT WILL BE GIVEN HERE FOR THE ASIO
130CODE BELOW</strong>. Please raise any questions or problems that you have with how to implement
131this sort of stuff in ASIO
132on <a href="https://stackoverflow.com/questions/tagged/boost-asio">Stackoverflow #boost-asio</a>.</p>
133</div>
134</div>
135
136
137<p>The real world, production-level recipe can be found at the bottom of this page.
138You ought to use that in any real world use case.</p>
139
140<p>It is however worth providing a walkthrough of a simplified edition of the real world
141recipe, as a lot of barely documented ASIO voodoo is involved. You should not
142use the code presented next in your own code, it is too simplified. But it should
143help you understand how the real implementation works.</p>
144
145<p>Firstly we need to define some helper type sugar and a factory function for wrapping
146any arbitrary third party completion token with that type sugar:</p>
147
148<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>
149<span class="p">{</span>
150  <span class="c1">// Type sugar for wrapping an external completion token
151</span><span class="c1"></span>  <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err"> </span><span class="nc">CompletionToken</span><span class="o">&gt;</span> <span class="k">struct</span> <span class="n">as_result_t</span>
152  <span class="p">{</span>
153    <span class="n">CompletionToken</span> <span class="n">token</span><span class="p">;</span>
154  <span class="p">};</span>
155<span class="p">}</span>  <span class="c1">// namespace detail
156</span><span class="c1"></span>
157<span class="c1">// Factory function for wrapping a third party completion token with
158</span><span class="c1">// our type sugar
159</span><span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err"> </span><span class="nc">CompletionToken</span><span class="o">&gt;</span>  <span class="c1">//
160</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">&amp;&amp;</span><span class="n">token</span><span class="p">)</span>
161<span class="p">{</span>
162  <span class="k">return</span> <span class="n">detail</span><span class="o">::</span><span class="n">as_result_t</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o">&lt;</span><span class="n">CompletionToken</span><span class="o">&gt;&gt;</span><span class="p">{</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">CompletionToken</span><span class="o">&gt;</span><span class="p">(</span><span class="n">token</span><span class="p">)};</span>
163<span class="p">};</span>
164</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>
165
166
167<p>Next we tell ASIO about a new completion token it ought to recognise by specialising
168<a href="https://www.boost.org/doc/libs/develop/doc/html/boost_asio/reference/async_result.html"><code>async_result</code></a>:</p>
169
170<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
171</span><span class="c1">// from our as_result() factory function. This implementation is
172</span><span class="c1">// for functions with handlers void(error_code, T) only.
173</span><span class="c1"></span><span class="k">template</span> <span class="o">&lt;</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">&gt;</span>                        <span class="c1">//
174</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">&lt;</span><span class="n">detail</span><span class="o">::</span><span class="n">as_result_t</span><span class="o">&lt;</span><span class="n">CompletionToken</span><span class="o">&gt;</span><span class="p">,</span>  <span class="c1">//
175</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">&gt;</span>                   <span class="c1">//
176</span><span class="c1"></span>
177<span class="p">{</span>
178  <span class="c1">// The result type we shall return
179</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">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">error_code</span><span class="o">&gt;</span><span class="p">;</span>
180  <span class="c1">// The awaitable type to be returned by the initiating function,
181</span><span class="c1"></span>  <span class="c1">// the co_await of which will yield a result_type
182</span><span class="c1"></span>  <span class="k">using</span> <span class="n">return_type</span> <span class="o">=</span> <span class="c1">//
183</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">&lt;</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">&gt;</span> <span class="c1">//
184</span><span class="c1"></span>  <span class="o">::</span><span class="n">return_type</span><span class="p">;</span>
185</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>
186
187
188<p>There are a couple tricky parts to understand. First of all, we want our
189<code>async_result</code> specialization to work, in particular, with the <code>async_result</code> for
190ASIO&rsquo;s
191<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>.
192With this token, the <code>async_result</code> specialization takes the form with a static
193<code>initiate</code> method which defers initiation of the asynchronous operation until,
194for example,
195<code>co_await</code> is called on the returned <code>awaitable</code>. Thus, our <code>async_result</code>
196specialization will take the same form. With this in mind, we need only
197understand how our specialization will implement its <code>initiate</code> method. The trick
198is that it will pass the initiation work off to an <code>async_result</code> for the
199supplied completion token type with a completion handler which consumes <code>result&lt;T&gt;</code>.
200Our <code>async_result</code> is thus just a simple wrapper over this underlying
201<code>async_result</code>, but we inject a completion handler with the
202<code>void(error_code, size_t)</code> signature which constructs from that a <code>result</code>:</p>
203
204<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
205</span><span class="c1"></span>  <span class="c1">// handler
206</span><span class="c1"></span>  <span class="k">template</span> <span class="o">&lt;</span><span class="k">class</span><span class="err"> </span><span class="nc">Handler</span><span class="o">&gt;</span>
207  <span class="k">struct</span> <span class="n">completion_handler</span> <span class="p">{</span>
208    <span class="c1">// Our completion handler spec
209</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>
210    <span class="p">{</span>
211      <span class="c1">// Call the underlying completion handler, whose
212</span><span class="c1"></span>      <span class="c1">// completion function is void(result_type)
213</span><span class="c1"></span>      <span class="k">if</span><span class="p">(</span><span class="n">ec</span><span class="p">)</span>
214      <span class="p">{</span>
215        <span class="c1">// Complete with a failed result
216</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>
217        <span class="k">return</span><span class="p">;</span>
218      <span class="p">}</span>
219      <span class="c1">// Complete with a successful result
220</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>
221    <span class="p">}</span>
222
223    <span class="n">Handler</span> <span class="n">_handler</span><span class="p">;</span>
224  <span class="p">};</span>
225
226  <span class="c1">// NOTE the initiate member function initiates the async operation,
227</span><span class="c1"></span>  <span class="c1">// and we want to defer to what would be the initiation of the
228</span><span class="c1"></span>  <span class="c1">// async_result whose handler signature is void(result_type).
229</span><span class="c1"></span>  <span class="k">template</span> <span class="o">&lt;</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">&gt;</span>
230  <span class="k">static</span> <span class="n">return_type</span>
231  <span class="n">initiate</span><span class="p">(</span>
232    <span class="n">Initiation</span><span class="o">&amp;&amp;</span> <span class="n">init</span><span class="p">,</span>
233    <span class="n">detail</span><span class="o">::</span><span class="n">as_result_t</span><span class="o">&lt;</span><span class="n">CompletionToken</span><span class="o">&gt;&amp;&amp;</span> <span class="n">token</span><span class="p">,</span>
234    <span class="n">Args</span><span class="o">&amp;&amp;</span><span class="p">...</span> <span class="n">args</span><span class="p">)</span>
235  <span class="p">{</span>
236    <span class="c1">// The async_initiate&lt;CompletionToken, void(result_type)&gt; helper
237</span><span class="c1"></span>    <span class="c1">// function will invoke the async initiation method of the
238</span><span class="c1"></span>    <span class="c1">// async_result&lt;CompletionToken, void(result_type)&gt;, as desired.
239</span><span class="c1"></span>    <span class="c1">// Instead of CompletionToken and void(result_type)	we start with
240</span><span class="c1"></span>    <span class="c1">// detail::as_result_t&lt;CompletionToken&gt; and void(ec, T), so
241</span><span class="c1"></span>    <span class="c1">// the inputs need to be massaged then passed along.
242</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">&lt;</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">&gt;</span><span class="p">(</span>
243      <span class="c1">// create a new initiation which wraps the provided init
244</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">&lt;</span><span class="n">Initiation</span><span class="o">&gt;</span><span class="p">(</span><span class="n">init</span><span class="p">)](</span>
245        <span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">handler</span><span class="p">,</span> <span class="k">auto</span><span class="o">&amp;&amp;</span><span class="p">...</span> <span class="n">initArgs</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
246        <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>
247          <span class="c1">// we wrap the handler in the converting completion_handler from
248</span><span class="c1"></span>          <span class="c1">// above, and pass along the args
249</span><span class="c1"></span>          <span class="n">completion_handler</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="n">handler</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="p">{</span>
250            <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="n">handler</span><span class="p">)</span><span class="o">&gt;</span><span class="p">(</span><span class="n">handler</span><span class="p">)},</span>
251          <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="n">initArgs</span><span class="p">)</span><span class="o">&gt;</span><span class="p">(</span><span class="n">initArgs</span><span class="p">)...);</span>
252      <span class="p">},</span>
253      <span class="c1">// the new initiation is called with the handler unwrapped from
254</span><span class="c1"></span>      <span class="c1">// the token, and the original initiation arguments.
255</span><span class="c1"></span>      <span class="n">token</span><span class="p">.</span><span class="n">token</span><span class="p">,</span>
256      <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Args</span><span class="o">&gt;</span><span class="p">(</span><span class="n">args</span><span class="p">)...);</span>
257  <span class="p">}</span>
258<span class="p">};</span>
259</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>
260
261
262<p>To use, simply wrap the third party completion token with <code>as_result</code> to cause
263ASIO to return from <code>co_await</code> a <code>result</code> instead of throwing exceptions on
264failure:</p>
265<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>
266
267<span class="n">outcome</span><span class="o">::</span><span class="n">result</span><span class="o">&lt;</span><span class="n">size_t</span><span class="p">,</span> <span class="n">error_code</span><span class="o">&gt;</span> <span class="n">bytesread</span> <span class="o">=</span>
268  <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>
269</code></pre></div>
270<p>The real world production-level implementation below is a lot more complex than the
271above which has been deliberately simplified to aid exposition. The above
272should help you get up and running with the below, eventually.</p>
273
274<p>One again I would like to remind you that Outcome is not the appropriate place
275to seek help with ASIO voodoo. Please ask on
276<a href="https://stackoverflow.com/questions/tagged/boost-asio">Stackoverflow #boost-asio</a>.</p>
277
278<hr />
279
280<p>Here follows the real world, production-level adapation of Outcome into
281ASIO, written and maintained by <a href="https://github.com/cstratopoulos">Christos Stratopoulos</a>.
282If the following does not load due to Javascript being disabled, you can visit the gist at
283<a href="https://gist.github.com/cstratopoulos/901b5cdd41d07c6ce6d83798b09ecf9b/863c1dbf3b063a5ff9ff2bdd834242ead556e74e">https://gist.github.com/cstratopoulos/901b5cdd41d07c6ce6d83798b09ecf9b/863c1dbf3b063a5ff9ff2bdd834242ead556e74e</a>.</p>
284
285<script type="application/javascript" src="//gist.github.com/cstratopoulos/901b5cdd41d07c6ce6d83798b09ecf9b/863c1dbf3b063a5ff9ff2bdd834242ead556e74e.js"></script>
286
287
288        </div><p><small>Last revised: August 06, 2019 at 10:42:06 &#43;0100</small></p>
289<hr>
290<div class="spirit-nav">
291<a accesskey="p" href="../recipes/asio-integration.html"><img src="../images/prev.png" alt="Prev"></a>
292    <a accesskey="u" href="../recipes.html"><img src="../images/up.png" alt="Up"></a>
293    <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>
294</html>
295