{"id":108446,"date":"2023-07-13T07:00:00","date_gmt":"2023-07-13T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108446"},"modified":"2023-07-13T06:36:59","modified_gmt":"2023-07-13T13:36:59","slug":"20230713-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230713-00\/?p=108446","title":{"rendered":"How to clone a Windows Runtime vector in the face of possible concurrent modification, part 2"},"content":{"rendered":"<p>Last time, we <a title=\"How to clone a Windows Runtime vector in the face of possible concurrent modification, part 1\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230712-00\/?p=108412\"> developed a pattern for cloning a Windows Runtime vector in the face of possible concurrent modification<\/a>. Let&#8217;s try to make a function out of this pattern.<\/p>\n<pre>template&lt;typename V&gt;\r\nauto clone_as_vector(V const&amp; v)\r\n-&gt; std::vector&lt;decltype(v.GetAt(0))&gt;\r\n{\r\n    using T = decltype(v.GetAt(0));\r\n    std::vector&lt;T&gt; temp;\r\n    uint32_t expected;\r\n    uint32_t actual;\r\n    do {\r\n        expected = v.Size();\r\n        temp.resize(expected + 1, <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220504-00\/?p=106569\">winrt_empty_value<\/a>&lt;T&gt;());\r\n        actual = v.GetMany(0, temp);\r\n    } while (actual &gt; expected);\r\n    temp.erase(temp.begin() + actual, temp.end());\r\n    return temp;\r\n}\r\n\r\ntemplate&lt;typename V&gt;\r\nauto CloneVector(V const&amp; v)\r\n-&gt; winrt::Windows::Foundation::\r\n        Collections::IVector&lt;decltype(v.GetAt(0))&gt;\r\n{\r\n    return winrt::multi_threaded_vector(\r\n        clone_as_vector(v));\r\n}\r\n<\/pre>\n<p>There are some sneaky bits here.<\/p>\n<p>First of all, we make <code>clone_<wbr \/>as_<wbr \/>vector<\/code> generic in that all it requires is that the <code>v<\/code> parameter support <code>GetAt()<\/code> and <code>GetMany()<\/code>. This allows the <code>clone_<wbr \/>as_<wbr \/>vector<\/code> to work with both <code>IVector<\/code> and <code>IVectorView<\/code>.<\/p>\n<p>Second, we use an explicit trailing return type instead of just letting the compiler figure it out from the <code>return<\/code> statement. This allow SFINAE to remove the function from consideration, allowing us to define other versions of <code>clone_<wbr \/>as_<wbr \/>vector<\/code> that work for other collection types.\u00b9<\/p>\n<p>This seems to work, until we run into <code>IVector&lt;bool&gt;<\/code>, because that cause the <code>clone_<wbr \/>as_<wbr \/>vector<\/code> function to create a <code>std::vector&lt;bool&gt;<\/code>.<\/p>\n<p>Uh-oh.<\/p>\n<p>We&#8217;ll try to fix that next time.<\/p>\n<p>\u00b9 Though our trailing return type validates only that <code>GetAt()<\/code> works. This means that it will accidentally activate for <code>Bindable\u00adVector<\/code> and <code>Bindable\u00adVector\u00adView<\/code>, which have <code>GetAt()<\/code> but not <code>GetMany()<\/code>. I guess we could fix that by adding more junk:<\/p>\n<pre>template&lt;typename V&gt;\r\nauto clone_as_vector(V const&amp; v)\r\n-&gt; std::enable_if_t&lt;\r\n    std::is_integral_v&lt;decltype(v.GetMany(0, {}))&gt;,\r\n    std::vector&lt;decltype(v.GetAt(0))&gt;&gt;\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Trying to make a generic solution.<\/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-108446","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Trying to make a generic solution.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108446","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=108446"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108446\/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=108446"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108446"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108446"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}