Insane_DNS/libraries/asio-1.28.1/doc/asio/overview/model/completion_tokens.html

326 lines
31 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Completion Tokens</title>
<link rel="stylesheet" href="../../../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../../index.html" title="Asio">
<link rel="up" href="../model.html" title="Asynchronous Model">
<link rel="prev" href="cancellation.html" title="Cancellation">
<link rel="next" href="library_elements.html" title="Supporting Library Elements">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr><td valign="top"><img alt="asio C++ library" width="250" height="60" src="../../../asio.png"></td></tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="cancellation.html"><img src="../../../prev.png" alt="Prev"></a><a accesskey="u" href="../model.html"><img src="../../../up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../home.png" alt="Home"></a><a accesskey="n" href="library_elements.html"><img src="../../../next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="asio.overview.model.completion_tokens"></a><a class="link" href="completion_tokens.html" title="Completion Tokens">Completion Tokens</a>
</h4></div></div></div>
<p>
<span class="inlinemediaobject"><img src="../../../completion_token_model.png" width="436"></span>
</p>
<p>
A key goal of Asio's asynchronous model is to support multiple composition
mechanisms. This is achieved via a <span class="emphasis"><em>completion token</em></span>,
which the user passes to an asynchronous operation's initiating function
to customise the API surface of the library. By convention, the completion
token is the final argument to an asynchronous operation's initiating function.
</p>
<p>
For example, if the user passes a lambda (or other function object) as
the completion token, the asynchronous operation behaves as previously
described: the operation begins, and when the operation completes the result
is passed to the lambda.
</p>
<pre class="programlisting"><span class="identifier">socket</span><span class="special">.</span><span class="identifier">async_read_some</span><span class="special">(</span><span class="identifier">buffer</span><span class="special">,</span>
<span class="special">[](</span><span class="identifier">error_code</span> <span class="identifier">e</span><span class="special">,</span> <span class="identifier">size_t</span><span class="special">)</span>
<span class="special">{</span>
<span class="comment">// ...</span>
<span class="special">}</span>
<span class="special">);</span>
</pre>
<p>
When the user passes the <a class="link" href="../../reference/use_future.html" title="use_future">use_future</a>
completion token, the operation behaves as though implemented in terms
of a <code class="computeroutput"><span class="identifier">promise</span></code> and <code class="computeroutput"><span class="identifier">future</span></code> pair. The initiating function
does not just launch the operation, but also returns a future that may
be used to await the result.
</p>
<pre class="programlisting"><span class="identifier">future</span><span class="special">&lt;</span><span class="identifier">size_t</span><span class="special">&gt;</span> <span class="identifier">f</span> <span class="special">=</span>
<span class="identifier">socket</span><span class="special">.</span><span class="identifier">async_read_some</span><span class="special">(</span>
<span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">use_future</span>
<span class="special">);</span>
<span class="comment">// ...</span>
<span class="identifier">size_t</span> <span class="identifier">n</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
</pre>
<p>
Similarly, when the user passes the <a class="link" href="../../reference/use_awaitable.html" title="use_awaitable">use_awaitable</a>
completion token, the initiating function behaves as though it is an <code class="computeroutput"><span class="identifier">awaitable</span></code>-based coroutine <sup>[<a name="asio.overview.model.completion_tokens.f0" href="#ftn.asio.overview.model.completion_tokens.f0" class="footnote">6</a>]</sup>. However, in this case the initiating function does not launch
the asynchronous operation directly. It only returns the <code class="computeroutput"><span class="identifier">awaitable</span></code>, which in turn launches the
operation when it is co_await-ed.
</p>
<pre class="programlisting"><span class="identifier">awaitable</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span> <span class="identifier">foo</span><span class="special">()</span>
<span class="special">{</span>
<span class="identifier">size_t</span> <span class="identifier">n</span> <span class="special">=</span>
<span class="identifier">co_await</span> <span class="identifier">socket</span><span class="special">.</span><span class="identifier">async_read_some</span><span class="special">(</span>
<span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">use_awaitable</span>
<span class="special">);</span>
<span class="comment">// ...</span>
<span class="special">}</span>
</pre>
<p>
Finally, the <a class="link" href="../../reference/yield_context.html" title="yield_context">yield_context</a>
completion token causes the initiating function to behave as a synchronous
operation within the context of a stackful coroutine. It not only begins
the asynchronous operation, but blocks the stackful coroutine until it
is complete. From the point of the stackful coroutine, it is a synchronous
operation.
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">foo</span><span class="special">(</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield_context</span> <span class="identifier">yield</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">size_t</span> <span class="identifier">n</span> <span class="special">=</span> <span class="identifier">socket</span><span class="special">.</span><span class="identifier">async_read_some</span><span class="special">(</span><span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">yield</span><span class="special">);</span>
<span class="comment">// ...</span>
<span class="special">}</span>
</pre>
<p>
All of these uses are supported by a single implementation of the <code class="computeroutput"><span class="identifier">async_read_some</span></code> initiating function.
</p>
<p>
To achieve this, an asynchronous operation must first specify a <span class="emphasis"><em>completion
signature</em></span> (or, possibly, signatures) that describes the arguments
that will be passed to its completion handler.
</p>
<p>
Then, the operation's initiating function takes the completion signature,
completion token, and its internal implementation and passes them to the
<span class="emphasis"><em>async_result</em></span> trait. The <code class="computeroutput"><span class="identifier">async_result</span></code>
trait is a customisation point that combines these to first produce a concrete
completion handler, and then launch the operation.
</p>
<p>
<span class="inlinemediaobject"><img src="../../../completion_token_transform.png" width="856"></span>
</p>
<p>
To see this in practice, let's use a detached thread to adapt a synchronous
operation into an asynchronous one:<sup>[<a name="asio.overview.model.completion_tokens.f1" href="#ftn.asio.overview.model.completion_tokens.f1" class="footnote">7</a>]</sup>
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span>
<span class="identifier">completion_token_for</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">size_t</span><span class="special">)&gt;</span> <a class="co" name="asio.overview.model.completion_tokens.c0" href="completion_tokens.html#asio.overview.model.completion_tokens.c1"><img src="../../../1.png" alt="1" border="0"></a>
<span class="identifier">CompletionToken</span><span class="special">&gt;</span>
<span class="keyword">auto</span> <span class="identifier">async_read_some</span><span class="special">(</span>
<span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span><span class="special">&amp;</span> <span class="identifier">s</span><span class="special">,</span>
<span class="keyword">const</span> <span class="identifier">mutable_buffer</span><span class="special">&amp;</span> <span class="identifier">b</span><span class="special">,</span>
<span class="identifier">CompletionToken</span><span class="special">&amp;&amp;</span> <span class="identifier">token</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">auto</span> <span class="identifier">init</span> <span class="special">=</span> <span class="special">[](</span> <a class="co" name="asio.overview.model.completion_tokens.c2" href="completion_tokens.html#asio.overview.model.completion_tokens.c3"><img src="../../../2.png" alt="2" border="0"></a>
<span class="keyword">auto</span> <span class="identifier">completion_handler</span><span class="special">,</span>
<span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span><span class="special">*</span> <span class="identifier">s</span><span class="special">,</span>
<span class="keyword">const</span> <span class="identifier">mutable_buffer</span><span class="special">&amp;</span> <span class="identifier">b</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">thread</span><span class="special">(</span> <a class="co" name="asio.overview.model.completion_tokens.c4" href="completion_tokens.html#asio.overview.model.completion_tokens.c5"><img src="../../../3.png" alt="3" border="0"></a>
<span class="special">[](</span>
<span class="keyword">auto</span> <span class="identifier">completion_handler</span><span class="special">,</span>
<span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span><span class="special">*</span> <span class="identifier">s</span><span class="special">,</span>
<span class="keyword">const</span> <span class="identifier">mutable_buffer</span><span class="special">&amp;</span> <span class="identifier">b</span>
<span class="special">)</span>
<span class="special">{</span>
<span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">;</span>
<span class="identifier">size_t</span> <span class="identifier">n</span> <span class="special">=</span> <span class="identifier">s</span><span class="special">-&gt;</span><span class="identifier">read_some</span><span class="special">(</span><span class="identifier">b</span><span class="special">,</span> <span class="identifier">ec</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">completion_handler</span><span class="special">)(</span><span class="identifier">ec</span><span class="special">,</span> <span class="identifier">n</span><span class="special">);</span> <a class="co" name="asio.overview.model.completion_tokens.c6" href="completion_tokens.html#asio.overview.model.completion_tokens.c7"><img src="../../../4.png" alt="4" border="0"></a>
<span class="special">},</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">completion_handler</span><span class="special">),</span>
<span class="identifier">s</span><span class="special">,</span>
<span class="identifier">b</span>
<span class="special">).</span><span class="identifier">detach</span><span class="special">();</span>
<span class="special">};</span>
<span class="keyword">return</span> <span class="identifier">async_result</span><span class="special">&lt;</span> <a class="co" name="asio.overview.model.completion_tokens.c8" href="completion_tokens.html#asio.overview.model.completion_tokens.c9"><img src="../../../5.png" alt="5" border="0"></a>
<span class="identifier">decay_t</span><span class="special">&lt;</span><span class="identifier">CompletionToken</span><span class="special">&gt;,</span>
<span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">size_t</span><span class="special">)</span>
<span class="special">&gt;::</span><span class="identifier">initiate</span><span class="special">(</span>
<span class="identifier">init</span><span class="special">,</span> <a class="co" name="asio.overview.model.completion_tokens.c10" href="completion_tokens.html#asio.overview.model.completion_tokens.c11"><img src="../../../6.png" alt="6" border="0"></a>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="identifier">CompletionToken</span><span class="special">&gt;(</span><span class="identifier">token</span><span class="special">),</span> <a class="co" name="asio.overview.model.completion_tokens.c12" href="completion_tokens.html#asio.overview.model.completion_tokens.c13"><img src="../../../7.png" alt="7" border="0"></a>
<span class="special">&amp;</span><span class="identifier">s</span><span class="special">,</span> <a class="co" name="asio.overview.model.completion_tokens.c14" href="completion_tokens.html#asio.overview.model.completion_tokens.c15"><img src="../../../8.png" alt="8" border="0"></a>
<span class="identifier">b</span>
<span class="special">);</span>
<span class="special">}</span>
</pre>
<div class="calloutlist"><table border="0" summary="Callout list">
<tr>
<td width="5%" valign="top" align="left"><p><a name="asio.overview.model.completion_tokens.c1"></a><a href="#asio.overview.model.completion_tokens.c0"><img src="../../../1.png" alt="1" border="0"></a> </p></td>
<td valign="top" align="left"><p>
The <code class="computeroutput"><span class="identifier">completion_token_for</span></code>
concept checks whether the user-supplied completion token will satisfy
the specified completion signature. For older versions of C++, simply
use <code class="computeroutput"><span class="keyword">typename</span></code> here instead.
</p></td>
</tr>
<tr>
<td width="5%" valign="top" align="left"><p><a name="asio.overview.model.completion_tokens.c3"></a><a href="#asio.overview.model.completion_tokens.c2"><img src="../../../2.png" alt="2" border="0"></a> </p></td>
<td valign="top" align="left"><p>
Define a function object that contains the code to launch the asynchronous
operation. This is passed the concrete completion handler, followed
by any additional arguments that were passed through the <code class="computeroutput"><span class="identifier">async_result</span></code> trait.
</p></td>
</tr>
<tr>
<td width="5%" valign="top" align="left"><p><a name="asio.overview.model.completion_tokens.c5"></a><a href="#asio.overview.model.completion_tokens.c4"><img src="../../../3.png" alt="3" border="0"></a> </p></td>
<td valign="top" align="left"><p>
The body of the function object spawns a new thread to perform the
operation.
</p></td>
</tr>
<tr>
<td width="5%" valign="top" align="left"><p><a name="asio.overview.model.completion_tokens.c7"></a><a href="#asio.overview.model.completion_tokens.c6"><img src="../../../4.png" alt="4" border="0"></a> </p></td>
<td valign="top" align="left"><p>
Once the operation completes, the completion handler is passed the
result.
</p></td>
</tr>
<tr>
<td width="5%" valign="top" align="left"><p><a name="asio.overview.model.completion_tokens.c9"></a><a href="#asio.overview.model.completion_tokens.c8"><img src="../../../5.png" alt="5" border="0"></a> </p></td>
<td valign="top" align="left"><p>
The <code class="computeroutput"><span class="identifier">async_result</span></code> trait
is passed the (decayed) completion token type, and the completion signatures
of the asynchronous operation.
</p></td>
</tr>
<tr>
<td width="5%" valign="top" align="left"><p><a name="asio.overview.model.completion_tokens.c11"></a><a href="#asio.overview.model.completion_tokens.c10"><img src="../../../6.png" alt="6" border="0"></a> </p></td>
<td valign="top" align="left"><p>
Call the traits <code class="computeroutput"><span class="identifier">initiate</span></code>
member function, first passing the function object that launches the
operation.
</p></td>
</tr>
<tr>
<td width="5%" valign="top" align="left"><p><a name="asio.overview.model.completion_tokens.c13"></a><a href="#asio.overview.model.completion_tokens.c12"><img src="../../../7.png" alt="7" border="0"></a> </p></td>
<td valign="top" align="left"><p>
Next comes the forwarded completion token. The trait implementation
will convert this into a concrete completion handler.
</p></td>
</tr>
<tr>
<td width="5%" valign="top" align="left"><p><a name="asio.overview.model.completion_tokens.c15"></a><a href="#asio.overview.model.completion_tokens.c14"><img src="../../../8.png" alt="8" border="0"></a> </p></td>
<td valign="top" align="left"><p>
Finally, pass any additional arguments for the function object. Assume
that these may be decay-copied and moved by the trait implementation.
</p></td>
</tr>
</table></div>
<p>
In practice we should call the <a class="link" href="../../reference/async_initiate.html" title="async_initiate">async_initiate</a>
helper function, rather than use the <code class="computeroutput"><span class="identifier">async_result</span></code>
trait directly. The <code class="computeroutput"><span class="identifier">async_initiate</span></code>
function automatically performs the necessary decay and forward of the
completion token, and also enables backwards compatibility with legacy
completion token implementations.
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span>
<span class="identifier">completion_token_for</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">size_t</span><span class="special">)&gt;</span>
<span class="identifier">CompletionToken</span><span class="special">&gt;</span>
<span class="keyword">auto</span> <span class="identifier">async_read_some</span><span class="special">(</span>
<span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span><span class="special">&amp;</span> <span class="identifier">s</span><span class="special">,</span>
<span class="keyword">const</span> <span class="identifier">mutable_buffer</span><span class="special">&amp;</span> <span class="identifier">b</span><span class="special">,</span>
<span class="identifier">CompletionToken</span><span class="special">&amp;&amp;</span> <span class="identifier">token</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">auto</span> <span class="identifier">init</span> <span class="special">=</span> <span class="comment">/* ... as above ... */</span><span class="special">;</span>
<span class="keyword">return</span> <span class="identifier">async_initiate</span><span class="special">&lt;</span>
<span class="identifier">CompletionToken</span><span class="special">,</span>
<span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">size_t</span><span class="special">)</span>
<span class="special">&gt;(</span><span class="identifier">init</span><span class="special">,</span> <span class="identifier">token</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">s</span><span class="special">,</span> <span class="identifier">b</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
We can think of the completion token as a kind of proto completion handler.
In the case where we pass a function object (like a lambda) as the completion
token, it already satisfies the completion handler requirements. The async_result
primary template handles this case by trivially forwarding the arguments
through:
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">CompletionToken</span><span class="special">,</span> <span class="identifier">completion_signature</span><span class="special">...</span> <span class="identifier">Signatures</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">async_result</span>
<span class="special">{</span>
<span class="keyword">template</span> <span class="special">&lt;</span>
<span class="keyword">class</span> <span class="identifier">Initiation</span><span class="special">,</span>
<span class="identifier">completion_handler_for</span><span class="special">&lt;</span><span class="identifier">Signatures</span><span class="special">...&gt;</span> <span class="identifier">CompletionHandler</span><span class="special">,</span>
<span class="keyword">class</span><span class="special">...</span> <span class="identifier">Args</span><span class="special">&gt;</span>
<span class="keyword">static</span> <span class="keyword">void</span> <span class="identifier">initiate</span><span class="special">(</span>
<span class="identifier">Initiation</span><span class="special">&amp;&amp;</span> <span class="identifier">initiation</span><span class="special">,</span>
<span class="identifier">CompletionHandler</span><span class="special">&amp;&amp;</span> <span class="identifier">completion_handler</span><span class="special">,</span>
<span class="identifier">Args</span><span class="special">&amp;&amp;...</span> <span class="identifier">args</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="identifier">Initiation</span><span class="special">&gt;(</span><span class="identifier">initiation</span><span class="special">)(</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="identifier">CompletionHandler</span><span class="special">&gt;(</span><span class="identifier">completion_handler</span><span class="special">),</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="identifier">Args</span><span class="special">&gt;(</span><span class="identifier">args</span><span class="special">)...);</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
We can see here that this default implementation avoids copies of all arguments,
thus ensuring that eager initiation is as efficient as possible.
</p>
<p>
On the other hand, a lazy completion token (such as <code class="computeroutput"><span class="identifier">use_awaitable</span></code>
above) may capture these arguments for deferred launching of the operation.
For example, a specialisation for a trivial <a class="link" href="../../reference/deferred.html" title="deferred">deferred</a>
token (that simply packages the operation for later) might look something
like this:
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span><span class="identifier">completion_signature</span><span class="special">...</span> <span class="identifier">Signatures</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">deferred_t</span><span class="special">,</span> <span class="identifier">Signatures</span><span class="special">...&gt;</span>
<span class="special">{</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">Initiation</span><span class="special">,</span> <span class="keyword">class</span><span class="special">...</span> <span class="identifier">Args</span><span class="special">&gt;</span>
<span class="keyword">static</span> <span class="keyword">auto</span> <span class="identifier">initiate</span><span class="special">(</span><span class="identifier">Initiation</span> <span class="identifier">initiation</span><span class="special">,</span> <span class="identifier">deferred_t</span><span class="special">,</span> <span class="identifier">Args</span><span class="special">...</span> <span class="identifier">args</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="special">[</span>
<span class="identifier">initiation</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">initiation</span><span class="special">),</span>
<span class="identifier">arg_pack</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">make_tuple</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">args</span><span class="special">)...)</span>
<span class="special">](</span><span class="keyword">auto</span><span class="special">&amp;&amp;</span> <span class="identifier">token</span><span class="special">)</span> <span class="keyword">mutable</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">apply</span><span class="special">(</span>
<span class="special">[&amp;](</span><span class="keyword">auto</span><span class="special">&amp;&amp;...</span> <span class="identifier">args</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">decay_t</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">token</span><span class="special">)&gt;,</span> <span class="identifier">Signatures</span><span class="special">...&gt;::</span><span class="identifier">initiate</span><span class="special">(</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">initiation</span><span class="special">),</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">token</span><span class="special">)&gt;(</span><span class="identifier">token</span><span class="special">),</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">args</span><span class="special">)&gt;(</span><span class="identifier">args</span><span class="special">)...</span>
<span class="special">);</span>
<span class="special">},</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">arg_pack</span><span class="special">)</span>
<span class="special">);</span>
<span class="special">};</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<div class="footnotes">
<br><hr width="100" align="left">
<div class="footnote"><p><sup>[<a name="ftn.asio.overview.model.completion_tokens.f0" href="#asio.overview.model.completion_tokens.f0" class="para">6</a>] </sup>
The <a class="link" href="../../reference/awaitable.html" title="awaitable">awaitable</a> class template
is included with the Asio library as a return type for C++20 coroutines.
These coroutines can be trivially implemented in terms of other <code class="computeroutput"><span class="identifier">awaitable</span></code>-based coroutines.
</p></div>
<div class="footnote"><p><sup>[<a name="ftn.asio.overview.model.completion_tokens.f1" href="#asio.overview.model.completion_tokens.f1" class="para">7</a>] </sup>
For illustrative purposes only. Not recommended for real world use!
</p></div>
</div>
</div>
<div class="copyright-footer">Copyright © 2003-2023 Christopher M. Kohlhoff<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="cancellation.html"><img src="../../../prev.png" alt="Prev"></a><a accesskey="u" href="../model.html"><img src="../../../up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../home.png" alt="Home"></a><a accesskey="n" href="library_elements.html"><img src="../../../next.png" alt="Next"></a>
</div>
</body>
</html>