{"id":109259,"date":"2024-01-11T07:00:00","date_gmt":"2024-01-11T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109259"},"modified":"2024-01-11T06:44:17","modified_gmt":"2024-01-11T14:44:17","slug":"20240111-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240111-00\/?p=109259","title":{"rendered":"In C++\/WinRT, how can I await multiple coroutines and capture the results?, part 2"},"content":{"rendered":"<p>Instead of <a title=\"In C++\/WinRT, how can I await multiple coroutines and capture the results?, part 1\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240110-00\/?p=109256\"> replacing the awaiter so it doesn&#8217;t retrieve the results<\/a>, we can go ahead and collect the results, and then return them. The Windows Runtime doesn&#8217;t have a convenient way to return a strongly-typed heterogeneous collection. Structures must be declared in metadata, and returning a vector of <code>IInspectable<\/code>s is not strongly-typed.<\/p>\n<p>Fortunately, we can use <a title=\"A map through the three major coroutine series\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210504-01\/?p=105178\"> our friend <code>simple_task<\/code><\/a>, which has since been added to the <a href=\"https:\/\/github.com\/microsoft\/wil\"> Windows Implementation Library<\/a> as <code>wil::<wbr \/>task<\/code>.<\/p>\n<pre>template&lt;typename... Results&gt;\r\nwil::task&lt;std::tuple&lt;Results&gt;&gt;\r\nwhen_all_with_results(\r\n    winrt::Windows::Foundation::IAsyncOperation&lt;Results&gt;... asyncs)\r\n{\r\n    co_return std::make_tuple(co_await asyncs...);\r\n}\r\n\r\nauto [result1, result2] =\r\n    co_await when_all_with_results(Do1Async(), Do2Async());\r\n<\/pre>\n<p>We wish we could have written<\/p>\n<pre>template&lt;typename... Asyncs&gt;\r\nwil::task&lt;<span style=\"border: solid 1px currentcolor;\">auto<\/span>&gt;\r\nwhen_all_with_results(Asyncs... asyncs)\r\n{\r\n    co_return std::make_tuple(co_await asyncs...);\r\n}\r\n<\/pre>\n<p>but there is currently no facility in the C++ language for this sort of weirdo template placeholder usage.<\/p>\n<p>The above formulation does limit you to <code>IAsyncOperation&lt;T&gt;<\/code>, so you cannot use other awaitables with <code>when_all_with_results<\/code>, like <code>IAsync\u00adOperation\u00adWith\u00adProgress&lt;T, P&gt;<\/code>. Adding <code>IAsync\u00adOperation\u00adWith\u00adProgress&lt;T, P&gt;<\/code> support isn&#8217;t so bad, because the result type is available from both <code>IAsync\u00adOperation&lt;T&gt;<\/code> and <code>IAsync\u00adOperation\u00adWith\u00adProgress&lt;T, P&gt;<\/code> by checking the return type of <code>Get\u00adResult()<\/code>.<\/p>\n<pre>template&lt;typename... Asyncs&gt;\r\nwil::task&lt;std::tuple&lt;\r\n    decltype(std::declval&lt;Asyncs&gt;().GetResults())...&gt;&gt;\r\nwhen_all_with_results(Asyncs... asyncs)\r\n{\r\n    co_return std::make_tuple(co_await asyncs...);\r\n}\r\n<\/pre>\n<p>Or, taking advantage of trailing return types so we don&#8217;t need to go through the hassle of <code>declval<\/code>:<\/p>\n<pre>template&lt;typename... Asyncs&gt;\r\nauto\r\nwhen_all_with_results(Asyncs... asyncs) -&gt;\r\n    wil::task&lt;std::tuple&lt;\r\n        decltype(asyncs.GetResults())...&gt;&gt;\r\n{\r\n    co_return std::make_tuple(co_await asyncs...);\r\n}\r\n<\/pre>\n<p>Extending support to other types of awaitables, such as <code>wil::task<\/code>, means having to fire up a lot of infrastructure to <a title=\"How to wait for multiple C++ coroutines to complete before propagating failure, finding the awaiter\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230707-00\/?p=108402\"> figure out what the <code>co_await<\/code> return type is<\/a>.<\/p>\n<pre>template&lt;typename T&gt;\r\nusing await_result = decltype(std::declval&lt;\r\n        awaiter_finder::type&lt;T&gt;&gt;().await_resume());\r\n\r\ntemplate&lt;typename... Asyncs&gt;\r\nwil::task&lt;std::tuple&lt;await_result&lt;Asyncs&gt;...&gt;&gt;\r\nwhen_all_with_results(Asyncs... async)\r\n{\r\n    co_return std::make_tuple(co_await async...);\r\n}\r\n<\/pre>\n<p>Great, you solved one problem but introduced at least two new ones.<\/p>\n<p>First problem is that one of these awaitables might produce a C++ reference. This wasn&#8217;t a problem with <code>IAsyncOperation<\/code>, since that never produces a C++ reference, but arbitrary awaitables might do that. Another problem is that one of the <code>async<\/code> values might be an awaitable that completes with <code>void<\/code>. You can&#8217;t put a <code>void<\/code> inside a tuple.<\/p>\n<p>We&#8217;ll look more closely at these problems next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wrapping the results and returning them in a tuple.<\/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-109259","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Wrapping the results and returning them in a tuple.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109259","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=109259"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109259\/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=109259"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109259"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109259"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}