{"id":105173,"date":"2021-05-03T07:00:00","date_gmt":"2021-05-03T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105173"},"modified":"2021-05-03T06:10:39","modified_gmt":"2021-05-03T13:10:39","slug":"20210503-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210503-00\/?p=105173","title":{"rendered":"C++ coroutines: Converting among tasks that use the same promise"},"content":{"rendered":"<p>If the only difference between tasks is in the awaiter, then it&#8217;s possible to convert between them without the promise even knowing what happened. We have an example of this with our <code>simple_<wbr \/>task<\/code> and <code>com_<wbr \/>simple_<wbr \/>task<\/code>, which differ only in the awaiter produced by the <code>co_<wbr \/>await<\/code> operator. This means that we can actually convert between the two by simple wrapping the promise inside the other class:<\/p>\n<pre>    template&lt;typename T&gt;\r\n    struct simple_task : details::simple_task_base&lt;T&gt;\r\n    {\r\n        using base = details::simple_task_base&lt;T&gt;;\r\n        simple_task() noexcept = default;\r\n        simple_task(details::simple_promise&lt;T&gt;*\r\n            initial) noexcept : base(initial)\r\n            { this-&gt;promise-&gt;start(); }\r\n        <span style=\"color: blue;\">simple_task(com_aware_task&lt;T&gt;&amp;&amp; other) noexcept\r\n            : base(std::move(other)) { }<\/span>\r\n        ...\r\n    };\r\n\r\n    template&lt;typename T&gt;\r\n    struct com_aware_task : details::simple_task_base&lt;T&gt;\r\n    {\r\n        using base = details::simple_task_base&lt;T&gt;;\r\n        com_aware_task() noexcept = default;\r\n        com_aware_task(details::simple_promise&lt;T&gt;*\r\n            initial) noexcept : base(initial)\r\n            { this-&gt;promise-&gt;start(); }\r\n        <span style=\"color: blue;\">com_aware_task(simple_task&lt;T&gt;&amp;&amp; other) noexcept\r\n            : base(std::move(other)) { }<\/span>\r\n        ...\r\n    };\r\n<\/pre>\n<p>You can now take a <code>simple_<wbr \/>task&lt;T&gt;<\/code> and re-wrap it inside a <code>com_<wbr \/>aware_<wbr \/>task&lt;T&gt;<\/code>:<\/p>\n<pre>extern async_helpers::simple_task&lt;void&gt; SomethingAsync();\r\n\r\nauto task = com_aware_task&lt;void&gt;(SomethingAsync());\r\n<\/pre>\n<p>The <code>Something\u00adAsync<\/code> function returned a <code>simple_<wbr \/>task&lt;void&gt;<\/code>, but we converted it to a <code>com_<wbr \/>aware_<wbr \/>task&lt;void&gt;<\/code>.<\/p>\n<p>We can also do the same thing to convert a cold-start task to a simple task or com-aware task by adopting the promise and starting it. However, we cannot convert a hot-start task into a cold-start task because the task has already started; you can&#8217;t un-start a task.<\/p>\n<p>The last step here is to remove the need to retype the coroutine return value when performing the conversion. We do this by adding deduction guides.<\/p>\n<pre>    template&lt;typename T&gt;\r\n    simple_task(com_aware_task&lt;T&gt;&amp;&amp;) -&gt; simple_task&lt;T&gt;;\r\n    template&lt;typename T&gt;\r\n    com_aware_task(simple_task&lt;T&gt;&amp;&amp;) -&gt; com_aware_task&lt;T&gt;;\r\n<\/pre>\n<p>Now you can write<\/p>\n<pre>auto task = com_aware_task(SomethingAsync());\r\n<\/pre>\n<p>Next time, I&#8217;ll look at a dark corner of the coroutine specification and how danger lurks inside.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Keeping the promise in the dark.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-105173","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Keeping the promise in the dark.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105173","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=105173"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105173\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=105173"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105173"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105173"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}