{"id":104075,"date":"2020-08-12T07:00:00","date_gmt":"2020-08-12T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104075"},"modified":"2020-09-09T06:13:43","modified_gmt":"2020-09-09T13:13:43","slug":"20200812-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200812-00\/?p=104075","title":{"rendered":"Hidden constraints on the result type in Concurrency Runtime tasks"},"content":{"rendered":"<p>If you are using the Concurrency Runtime <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/parallel\/concrt\/reference\/task-class\"> <code>task&lt;T&gt;<\/code><\/a> to represent asynchronous activity, there are some hidden constraints on the type <code>T<\/code>. If you violate these constraints, the compiler will complain, but perhaps not in an obvious way.\u00b9<\/p>\n<p>If you try to create a <code>task&lt;T&gt;<\/code> where <code>T<\/code> does not have a public default constructor, then you get an error like<\/p>\n<pre style=\"white-space: pre-wrap;\">ppltasks.h: error C2280: 'Concurrency::details::_ResultHolder&lt;_ReturnType&gt;::_ResultHolder(void)': attempting to reference a deleted function\r\nwith _ReturnType = T\r\n<\/pre>\n<p>And if the <code>T<\/code> is not copyable, then you get something like<\/p>\n<pre style=\"white-space: pre-wrap;\">ppltasks.h: Error C2280: 'T::T(const T&amp;) noexcept' attempting to reference a deleted function\r\n<\/pre>\n<p>What&#8217;s going on?<\/p>\n<p>Let&#8217;s look at the copyability first. Task results must be copyable because the task result can be consumed multiple times in multiple ways. You can <code>get()<\/code> multiple times, and each time returns the task result. You can call <code>then()<\/code> multiple times, and each continuation is given the task result. If the task result were not copyable, then only one of the calls to <code>get()<\/code> or <code>then()<\/code> will get the result, and the others would get, um, a letter of apology?<\/p>\n<p>The requirement that the type be publicly constructible is a consequence of the fact that the task contains a copy of the <code>T<\/code>, and if the task hasn&#8217;t completed yet, then the <code>T<\/code> object needs to contains <i>something<\/i>, so the library just puts a default-constructed <code>T<\/code> in it. This requirement is confessed in the source code:<\/p>\n<pre>    \/\/ this means that the result type must have a public default ctor.\r\n    _ResultHolder&lt;_ReturnType&gt; _M_Result;\r\n<\/pre>\n<p>Okay, so how can you work around these limitations? We&#8217;ll look at that <a title=\"Working around the requirement that Concurrency Runtime task results must be default-constructible and copyable\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200813-00\/?p=104080\"> next time<\/a>.<\/p>\n<p>\u00b9 <b>Related reading<\/b>: <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200206-00\/?p=103414\"> Why does my C++\/WinRT project get errors of the form &#8220;<code>abi&lt;\u2026&gt;::\u2026<\/code> is abstract see reference to <code>producer&lt;\u2026&gt;<\/code>&#8220;?<\/a>, on the underappreciated need for libraries to generate comprehensible error messages when used incorrectly, and the difficulty of compiler error message meta-programming. For these two cases, the Concurrency Runtime could have added some <code>static_assert<\/code>s to generate custom error messages.<\/p>\n<pre>template&lt;typename _Type&gt;\r\nstruct _ResultHolder\r\n{\r\n    static_assert(std::is_default_constructible&lt;_Type&gt;::value,\r\n        \"The result type of a task must be default constructible\");\r\n    static_assert(std::is_copy_constructible&lt;T&gt;::value,\r\n        \"The result type of a task must be copy constructible\");\r\n\r\n    ....\r\n};\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>If you are using the Concurrency Runtime task&lt;T&gt; to represent asynchronous activity, there are some hidden constraints on the type T. If you violate these constraints, the compiler will complain, but perhaps not in an obvious way.\u00b9 If you try to create a task&lt;T&gt; where T does not have a public default constructor, then you [&hellip;]<\/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-104075","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>If you are using the Concurrency Runtime task&lt;T&gt; to represent asynchronous activity, there are some hidden constraints on the type T. If you violate these constraints, the compiler will complain, but perhaps not in an obvious way.\u00b9 If you try to create a task&lt;T&gt; where T does not have a public default constructor, then you [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104075","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=104075"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104075\/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=104075"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104075"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104075"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}