{"id":104160,"date":"2020-09-03T07:00:00","date_gmt":"2020-09-03T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104160"},"modified":"2020-09-09T06:09:11","modified_gmt":"2020-09-09T13:09:11","slug":"20200903-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200903-00\/?p=104160","title":{"rendered":"Rough edges in the when_all coroutine, part 1: Empty parameter list"},"content":{"rendered":"<p>Last time, we looked at how we could <a title=\"Synthesizing a when_all coroutine from pieces you already have\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200902-00\/?p=104155\"> write our own <code>when_all<\/code> coroutine that completes when all of its parameters have completed<\/a>. It turned out to be very simple, thanks to C++ fold expressions.<\/p>\n<pre>template &lt;typename... T&gt;\r\nWindows::Foundation::IAsyncAction when_all(T... async)\r\n{\r\n    (co_await async, ...);\r\n}\r\n<\/pre>\n<p>But there&#8217;s a problem in the edge case where the caller passes no parameters at all. This may not be something you do intentionally, but it could fall out of some other template metaprogramming algorithm where you discover that there is nothing to do, and the parameter pack expansion is empty. Or maybe it&#8217;s the base case of some recursive algorithm.<\/p>\n<p>In the case where there are no parameters, <code>when_all<\/code> is vacuously complete (nothing to wait for), but you get a compiler warning:<\/p>\n<pre>control reaches end of non-void function\r\n<\/pre>\n<p>What&#8217;s that about?<\/p>\n<p>If there are no parameters at all, then the fold expression has nothing to <code>co_await<\/code>, and per the language specification (<b>[tab:temp.fold.empty]<\/b>), a folded comma operator with no arguments, the result is <code>void()<\/code>. The effect is therefore this:<\/p>\n<pre>Windows::Foundation::IAsyncAction when_all()\r\n{\r\n    void();\r\n}\r\n<\/pre>\n<p>And now we see the problem. Since there is no <code>co_await<\/code>, <code>co_return<\/code> or <code>co_yield<\/code> anywhere in the body, the function is <i>not a coroutine<\/i>. It&#8217;s just a regular function that returns an <code>IAsync\u00adAction<\/code>, and it forgot to return one!<\/p>\n<p>We can fix this by adding a <code>co_return<\/code>. In the case where the parameter list is nonempty, the <code>co_return<\/code> is redundant but harmless, because falling off the end of a coroutine which produces a <code>void<\/code> is equivalent to performing a <code>co_return<\/code> just before the close-brace. The purpose of the explicit <code>co_return<\/code> is to ensure correct behavior when the parameter list is empty.<\/p>\n<p><a title=\"Rough edges in the when_all coroutine, part 2: Overloaded comma operator\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200904-00\/?p=104172\"> Next time<\/a>, another edge case.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve got plenty of nothing.<\/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-104160","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>I&#8217;ve got plenty of nothing.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104160","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=104160"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104160\/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=104160"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104160"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104160"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}