{"id":109797,"date":"2024-05-23T07:00:00","date_gmt":"2024-05-23T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109797"},"modified":"2024-05-23T10:54:57","modified_gmt":"2024-05-23T17:54:57","slug":"20240523-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240523-00\/?p=109797","title":{"rendered":"Creating a prepopulated Windows Runtime Vector from C++\/WinRT without going through an explicit <CODE>std::<WBR>vector<\/CODE>"},"content":{"rendered":"<p>Last time, we saw that <a title=\"If you have to create a Windows Runtime Vector from C++\/WinRT, do it as late as possible\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240522-00\/?p=109795\"> if you have to create a Windows Runtime Vector from C++\/WinRT, do it as late as possible<\/a>. And the extreme case of doing it as late as possible is creating it in the conversion function itself!<\/p>\n<p>We&#8217;ll start with the na\u00efve slow way:<\/p>\n<pre>namespace winrt\r\n{\r\n    using namespace winrt::Windows::Foundation;\r\n}\r\n\r\nwinrt::IVector&lt;winrt::Uri&gt; GetUris()\r\n{\r\n    auto v = winrt::multi_threaded_vector&lt;winrt::Uri&gt;();\r\n    v.Append(winrt::Uri(L\"https:\/\/microsoft.com\/\"));\r\n    v.Append(winrt::Uri(L\"https:\/\/contoso.com\/\"));\r\n    v.Append(winrt::Uri(L\"https:\/\/fabrikam.com\/\"));\r\n    return v;\r\n}\r\n<\/pre>\n<p>This follows the inefficient pattern we discussed yesterday, where we create an empty <code>IVector<\/code> and then use the <code>IVector<\/code> methods to append elements to it.<\/p>\n<p>We saw last time that we could do better by working with <code>std::<wbr \/>vector<\/code> first, and converting it to an <code>IVector<\/code> as a final step:<\/p>\n<pre>winrt::IVector&lt;winrt::Uri&gt; GetOptions()\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">std::vector&lt;winrt::Uri&gt; v;<\/span>\r\n    v.<span style=\"border: solid 1px currentcolor; border-bottom: none;\">push_back<\/span>(winrt::Uri(L\"https:\/\/microsoft.com\/\"));\r\n    v.<span style=\"border: 1px currentcolor; border-style: none solid;\">push_back<\/span>(winrt::Uri(L\"https:\/\/contoso.com\/\"));\r\n    v.<span style=\"border: solid 1px currentcolor; border-top: none;\">push_back<\/span>(winrt::Uri(L\"https:\/\/fabrikam.com\/\"));\r\n    return <span style=\"border: solid 1px currentcolor;\">winrt::multi_threaded_vector(std::move(v));<\/span>\r\n}\r\n<\/pre>\n<p>And now that you have a <code>std::<wbr \/>vector<\/code>, you can take advantage of vector-specific features like <code>emplace_<wbr \/>back<\/code>, which treats its arguments as parameters which will be used to construct a <code>winrt::Uri<\/code> object in place in the vector.<\/p>\n<pre>winrt::IVector&lt;winrt::Uri&gt; GetUris()\r\n{\r\n    std::vector&lt;winrt::Uri&gt; v;\r\n    v.<span style=\"border: solid 1px currentcolor; border-bottom: none;\">emplace_back(L\"https:\/\/microsoft.com\/\");<\/span>\r\n    v.<span style=\"border: 1px currentcolor; border-style: none solid;\">emplace_back(L\"https:\/\/contoso.com\/\");  <\/span>\r\n    v.<span style=\"border: solid 1px currentcolor; border-top: none;\">emplace_back(L\"https:\/\/fabrikam.com\/\"); <\/span>\r\n    return winrt::multi_threaded_vector(std::move(v));\r\n}\r\n<\/pre>\n<p>But there&#8217;s a way to do this without ever having to create a <code>std::<wbr \/>vector<\/code> variable at all: You can create the vector on the fly as a parameter!<\/p>\n<pre>winrt::IVector&lt;winrt::hstring&gt; GetUris()\r\n{\r\n    \/\/ Alternative 1\r\n    return winrt::multi_threaded_vector&lt;winrt::Uri&gt;({\r\n        winrt::Uri(L\"https:\/\/microsoft.com\/\"),\r\n        winrt::Uri(L\"https:\/\/contoso.com\/\"),\r\n        winrt::Uri(L\"https:\/\/fabrikam.com\/\"),\r\n    });\r\n\r\n    \/\/ Alternative 2\r\n    return winrt::multi_threaded_vector(std::vector{\r\n        winrt::Uri(L\"https:\/\/microsoft.com\/\"),\r\n        winrt::Uri(L\"https:\/\/contoso.com\/\"),\r\n        winrt::Uri(L\"https:\/\/fabrikam.com\/\"),\r\n    });\r\n}\r\n<\/pre>\n<p>You can&#8217;t say<\/p>\n<pre>    return winrt::multi_threaded_vector({\r\n        winrt::Uri(L\"https:\/\/microsoft.com\/\"),\r\n        winrt::Uri(L\"https:\/\/contoso.com\/\"),\r\n        winrt::Uri(L\"https:\/\/fabrikam.com\/\"),\r\n    });\r\n<\/pre>\n<p>because <code>multi_<wbr \/>threaded_<wbr \/>vector<\/code> cannot deduce the element type from the initializer list. (Maybe you can teach it and submit a pull request?)<\/p>\n<p>But what you can do is take advantage of the fact that if you do specify the element type, then <code>multi_<wbr \/>threaded_<wbr \/>vector<\/code> will know that it needs a <code>std::vector&lt;<wbr \/>winrt::<wbr \/>Uri&gt;<\/code>, and then compiler will see from the vector constructors that the braced list is an <code>initializer_<wbr \/>list&lt;winrt::<wbr \/>Uri&gt;<\/code>, and then the compiler will see that it knows how to construct a <code>winrt::<wbr \/>Uri<\/code> from a string literal, so it will automatically use the constructor to populate the initializer list. All this means that you don&#8217;t have to say <code>winrt::Uri<\/code> around each string:<\/p>\n<pre>winrt::IVector&lt;winrt::hstring&gt; GetUris()\r\n{\r\n    return winrt::multi_threaded_vector&lt;winrt::Uri&gt;({\r\n        L\"https:\/\/microsoft.com\/\",\r\n        L\"https:\/\/contoso.com\/\",\r\n        L\"https:\/\/fabrikam.com\/\",\r\n    });\r\n}\r\n<\/pre>\n<p>This is still a little frustrating because it does construct a bunch of temporary <code>winrt::Uri<\/code>s to go into the initializer list, which are then copied into the vector. Instead, you can use the two-iterator version and let the vector do the constructing in-place.<\/p>\n<pre>winrt::IVector&lt;winrt::hstring&gt; GetUris()\r\n{\r\n    static constexpr PCWSTR uris[] = {\r\n        L\"https:\/\/microsoft.com\/\",\r\n        L\"https:\/\/contoso.com\/\",\r\n        L\"https:\/\/fabrikam.com\/\",\r\n    };\r\n    return winrt::multi_threaded_vector&lt;winrt::Uri&gt;(\r\n        { std::begin(uris), std::end(uris) });\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Creating the vector inline.<\/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-109797","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Creating the vector inline.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109797","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=109797"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109797\/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=109797"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109797"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109797"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}