{"id":109973,"date":"2024-07-16T07:00:00","date_gmt":"2024-07-16T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109973"},"modified":"2024-06-24T10:49:03","modified_gmt":"2024-06-24T17:49:03","slug":"20240716-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240716-00\/?p=109973","title":{"rendered":"Creating an already-completed asynchronous activity in C++\/WinRT, part 6"},"content":{"rendered":"<p>Last time, we finished making <a title=\"Creating an already-completed asynchronous activity in C++\/WinRT, part 5\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240715-00\/?p=109971\"> generalized <code>Make\u00adCompleted<\/code> and <code>Make\u00adFailed<\/code> functions<\/a> for creating already-completed asynchronous activities in C++\/WinRT. We left off with the observation that it&#8217;s annoying having to write out the template type parameter all the time:<\/p>\n<pre>winrt::Windows::Foundation::IAsyncOperationWithProgress&lt;bool, WidgetSaveProgress&gt;\r\n    SaveChanges()\r\n{\r\n    \/\/ The widget is immutable, so there are no changes to save.\r\n    return MakeCompleted&lt;\r\n        winrt::Windows::Foundation::IAsyncOperationWithProgress&lt;\r\n            bool, WidgetSaveProgress&gt;&gt;(true);\r\n}\r\n<\/pre>\n<p>We can avoid the extra typing by returning a proxy object and let the conversion operator tell us what interface the caller wants.<\/p>\n<pre>template&lt;typename... Result&gt;\r\nstruct async_completed\r\n{\r\n    static_assert(sizeof...(Result) &lt;= 1);\r\n    std::tuple&lt;std::decay_t&lt;Result&gt;...&gt; m_result;\r\n\r\n    async_completed(Result&amp;&amp;... result) :\r\n        m_result(std::forward&lt;Result&gt;(result)...) {}\r\n\r\n    template&lt;typename Async&gt;\r\n    Async <a title=\"It's great that you provide operator overloads, but it's also nice to have names\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230605-00\/?p=108289\">as<\/a>() {\r\n        if constexpr (sizeof...(Result) == 0) {\r\n            co_return;\r\n        } else {\r\n            co_return std::move(std::get&lt;0&gt;(m_result));\r\n        }\r\n    }\r\n\r\n    template&lt;typename Async&gt;\r\n    operator Async() { return as&lt;Async&gt;(); }\r\n};\r\n\r\ntemplate&lt;typename Error&gt;\r\nstruct async_failed\r\n{\r\n    std::decay_t&lt;Error&gt; m_error;\r\n\r\n    async_failed(Error&amp;&amp; error) :\r\n        m_error(std::forward&lt;Error&gt;(error)) {}\r\n\r\n    template&lt;typename Async&gt;\r\n    operator Async() {\r\n        (void) co_await winrt::get_cancellation_token();\r\n        throw std::move(m_error);\r\n    }\r\n};\r\n<\/pre>\n<p>Now you can let the proxy convert to the desired type.<\/p>\n<pre>winrt::Windows::Foundation::IAsyncAction\r\n    SaveAsync()\r\n{\r\n    return async_completed();\r\n}\r\n\r\nwinrt::Windows::Foundation::IAsyncOperation&lt;bool&gt;\r\n    SaveAsync()\r\n{\r\n    return async_completed(false);\r\n}\r\n\r\nwinrt::Windows::Foundation::IAsyncAction\r\n    SaveAsync()\r\n{\r\n    return async_failed(winrt::hresult_access_denied());\r\n}\r\n<\/pre>\n<p>Now, for cases like this, the <code>async_completed<\/code> and <code>async_failed<\/code> are awfully awkward-looking. The more natural way to write the methods would be<\/p>\n<pre>winrt::Windows::Foundation::IAsyncAction\r\n    SaveAsync()\r\n{\r\n    co_return;\r\n}\r\n\r\nwinrt::Windows::Foundation::IAsyncOperation&lt;bool&gt;\r\n    SaveAsync()\r\n{\r\n    co_return false;\r\n}\r\n\r\nwinrt::Windows::Foundation::IAsyncAction\r\n    SaveAsync()\r\n{\r\n    (void) co_await winrt::get_cancellation_token();\r\n    throw winrt::hresult_access_denied();\r\n}\r\n<\/pre>\n<p>But sometimes you might want to create a failed or completed asynchronous activity outside of a coroutine, and for those cases, <code>async_<wbr \/>completed<\/code> and <code>async_<wbr \/>failed<\/code> might be handy.<\/p>\n<p>But wait, we&#8217;re firing up the coroutine infrastructure just to return a value or throw an exception. That feels like overkill. We&#8217;ll look into a direct implementation next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Let the conversion do the talking.<\/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-109973","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Let the conversion do the talking.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109973","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=109973"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109973\/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=109973"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109973"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109973"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}