{"id":109967,"date":"2024-07-12T07:00:00","date_gmt":"2024-07-12T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109967"},"modified":"2024-06-24T10:36:10","modified_gmt":"2024-06-24T17:36:10","slug":"20240712-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240712-00\/?p=109967","title":{"rendered":"Creating an already-completed asynchronous activity in C++\/WinRT, part 4"},"content":{"rendered":"<p>Last time, we <a title=\"Creating an already-completed asynchronous activity in C++\/WinRT, part 3\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240711-00\/?p=109965\"> created a generalized <code>Make\u00adCompleted<\/code> for creating an already-completed asynchronous activity in C++\/WinRT<\/a>. Today, we&#8217;ll try to do the same for <code>Make\u00adFailed<\/code>.<\/p>\n<p>In one sense, <code>Make\u00adFailed<\/code> is easier because the body is the same regardless of which of the four types of asynchronous activities you&#8217;re making.<\/p>\n<pre>winrt::Windows::Foundation::IAsyncAction\r\nMakeFailedAsyncAction(winrt::hresult_error error)\r\n{\r\n    (void) co_await winrt::get_cancellation_token();\r\n    throw error;\r\n}\r\n\r\ntemplate&lt;typename Progress&gt;\r\nwinrt::Windows::Foundation::IAsyncActionWithProgress&lt;Progress&gt;\r\nMakeFailedAsyncActionWithProgress(winrt::hresult_error error)\r\n{\r\n    (void) co_await winrt::get_cancellation_token();\r\n    throw error;\r\n}\r\n\r\ntemplate&lt;typename Result, typename Progress&gt;\r\nwinrt::Windows::Foundation::IAsyncOperation&lt;Result&gt;\r\nMakeFailedAsyncOperation(winrt::hresult_error error)\r\n{\r\n    (void) co_await winrt::get_cancellation_token();\r\n    throw error;\r\n}\r\n\r\ntemplate&lt;typename Result, typename Progress&gt;\r\nwinrt::Windows::Foundation::IAsyncOperationWithProgress&lt;Result, Progress&gt;\r\nMakeFailedAsyncOperationWithProgress(winrt::hresult_error error)\r\n{\r\n    (void) co_await winrt::get_cancellation_token();\r\n    throw error;\r\n}\r\n\r\n\/\/ Sample usage\r\nwinrt::Windows::Foundation::IAsyncOperation&lt;int&gt;\r\nGetSizeAsync()\r\n{\r\n    return MakeFailedAsyncOperation&lt;int&gt;(\r\n        winrt::hresult_not_implemented());\r\n}\r\n<\/pre>\n<p>This easily generalizes:<\/p>\n<pre>template&lt;typename Async&gt;\r\nAsync MakeFailed(winrt::hresult_error error)\r\n{\r\n    (void) co_await winrt::get_cancellation_token();\r\n    throw error;\r\n}\r\n<\/pre>\n<p>Unfortunately, it&#8217;s also wrong.<\/p>\n<p>Since we receive the exception in the form of a <code>hresult_<wbr \/>error<\/code> by value, anybody who passes a derived exception like <code>hresult_<wbr \/>access_<wbr \/>denied<\/code> will be subjected to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Object_slicing\"> slicing<\/a>. You might think to avoid slicing by taking the parameter by reference, but that runs into two problems. First, you are carrying a reference across a <code>co_await<\/code>, which may cause static analysis tools to get upset at you. Worse is that receiving the parameter as a reference doesn&#8217;t resolve the slicing because the <code>throw<\/code> throws only the <code>hresult_<wbr \/>error<\/code> portion of the exception. Fortunately, this second problem is a non-issue in this specific case because it is captured and reported at the ABI to the coroutine consumer as an <code>HRESULT<\/code> failure code from the <code>GetResults()<\/code> method, and the consumer will realize that the <code>HRESULT<\/code> is, say, <code>E_INVALIDARG<\/code> and reconstruct a <code>hresult_<wbr \/>invalid_<wbr \/>argument<\/code>.\u00b9<\/p>\n<p>The real problem is that <!-- backref: C++\/WinRT gotcha: Not all exceptions derive from hresult_error --> not all C++\/WinRT exceptions derive from <code>hresult_error<\/code>. What if somebody wants to make a <code>IAsyncAction<\/code> that failed with <code>std::<wbr \/>bad_<wbr \/>alloc<\/code>?<\/p>\n<p>So we&#8217;ll accept anything that C++\/WinRT supports, which is anything derived from <code>std::<wbr \/>exception<\/code> or <code>winrt::<wbr \/>hresult_<wbr \/>error<\/code>.<\/p>\n<pre>template&lt;typename Async, typename Error,\r\n    typename = std::enable_if_t&lt;\r\n        std::is_base_of_v&lt;std::exception, Error&gt; ||\r\n        std::is_base_of_v&lt;winrt::hresult_error, Error&gt;&gt;&gt;\r\nAsync MakeFailed(Error error)\r\n{\r\n    (void) co_await winrt::get_cancellation_token();\r\n    throw error;\r\n}\r\n<\/pre>\n<p>When dealing with coroutines or exceptions (and especially in our case here, which is coroutines <i>and<\/i> exceptions), you need to think about debuggability. Exceptions are nonlocal transfer, so it can be difficult to debug where an exception originated. And coroutines break up function execution into chunks, and most of the chunks run after the original call stack is lost, so that makes it even more frustrating. We&#8217;ll look into this next time.<\/p>\n<p>\u00b9 Related reading: <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231116-00\/?p=109023\"> What happened to the custom exception description I threw from a C++\/WinRT <code>IAsyncAction<\/code><\/a>? <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231102-00\/?p=108956\"> How come my custom exception message is lost when it is thrown from a <code>IAsyncAction<\/code>^<\/a>?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Failing is easy. Failing correctly is hard.<\/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-109967","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Failing is easy. Failing correctly is hard.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109967","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=109967"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109967\/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=109967"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109967"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109967"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}