{"id":104297,"date":"2020-09-25T07:00:00","date_gmt":"2020-09-25T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104297"},"modified":"2020-09-25T07:01:19","modified_gmt":"2020-09-25T14:01:19","slug":"20200925-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200925-00\/?p=104297","title":{"rendered":"Structured binding may be the new hotness, but we&#8217;ll always have std::tie"},"content":{"rendered":"<p>C++17 introduced <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/structured_binding\"> structured binding<\/a>, which lets you assign an expression to multiple variables.<\/p>\n<pre>auto [a,b] = std::pair(1, \"hello\");\r\n\/\/ int a = 1\r\n\/\/ char const* b = \"hello\"\r\n<\/pre>\n<p>However, this is for creating new variables to hold the result. If you want to assign the result to existing variables, then you can use the old standby <code>std::tie<\/code>.<\/p>\n<pre>int a;\r\nchar const* b;\r\nstd::tie(a, b) = std::pair(1, \"hello\");\r\n<\/pre>\n<p>This comes in handy in C++\/WinRT if you have a <code>winrt::com_array&lt;T&gt;<\/code> and you need to return it in its ABI form of a <code>uint32_t<\/code> coupled with a <code>T*<\/code>.<\/p>\n<pre>winrt::com_array&lt;int32_t&gt; CalculateResult();\r\n\r\nHRESULT GetInt32Array(uint32_t* size, int32_t** value) try\r\n{\r\n  *size = 0;\r\n  *value = nullptr;\r\n  std::tie(*size, *value) = winrt::detach_abi(CalculateResult());\r\n  return S_OK;\r\n}\r\ncatch (...) { return winrt::to_hresult(); }\r\n<\/pre>\n<p>When applied to a <code>com_array<\/code>, the <code>detach_abi<\/code> function returns a <code>std::pair<\/code> representing the size of the conformant array and a pointer to the start of the array. This is a form ready to be assigned to the tie of the two output parameters.<\/p>\n<p>The type of the pointer part of the return value of <code>detach_abi(com_array&lt;T&gt; a)<\/code> is a pointer to <!-- backref: Inside C++\/WinRT: How does C++\/WinRT represent ABI types? --> the C++\/WinRT ABI representation of <code>T<\/code>. Here are some examples:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th><code>T<\/code><\/th>\n<th><code>detach_abi(com_array&lt;T&gt;)<\/code> returns<\/th>\n<\/tr>\n<tr>\n<td><code>int32_t<\/code><\/td>\n<td><code>std::pair&lt;uint32_t, int32_t*&gt;<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>hstring<\/code><\/td>\n<td><code>std::pair&lt;uint32_t, void**&gt;<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>ISomething<\/code><\/td>\n<td><code>std::pair&lt;uint32_t, mystery_abi*&gt;<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<ul>\n<li>If you have a <code>com_array<\/code> of a scalar type, then you will get a pointer to a conformant array of that scalar type.<\/li>\n<li>If you have a <code>com_array<\/code> of a string type, then you will get a pointer to a conformant array of <code>void*<\/code>.<\/li>\n<li>If you have a <code>com_array<\/code> of a reference type, then you will get a pointer to a conformant array of mystery pointers.<\/li>\n<\/ul>\n<p>In the last case, you should just treat the resulting pointer as if it were a <code>void**<\/code>.<\/p>\n<pre>HRESULT GetNames(uint32_t* size, HSTRING** value) try\r\n{\r\n  *size = 0;\r\n  *value = nullptr;\r\n  std::tie(*size, reinterpret_cast&lt;void*&amp;&gt;(*value)) =\r\n    winrt::detach_abi(CalculateNames());\r\n  return S_OK;\r\n}\r\ncatch (...) { return winrt::to_hresult(); }\r\nHRESULT GetSomethingArray(uint32_t* size, ISomething*** value) try\r\n{\r\n  *size = 0;\r\n  *value = nullptr;\r\n  std::tie(*size, reinterpret_cast&lt;void*&amp;&gt;(*value)) =\r\n    winrt::detach_abi(CalculateSomethings());\r\n  return S_OK;\r\n}\r\ncatch (...) { return winrt::to_hresult(); }\r\n<\/pre>\n<p>Note that in both cases we reinterpret-cast the output pointer to just <code>void*<\/code>. Any pointer type can be assigned to <code>void*<\/code>, so we just use that to soak up the C++\/WinRT ABI pointer, without needing to know what it actually is.\u00b9<\/p>\n<p>\u00b9 The C++\/WinRT ABI requires that all data pointers have the same size and representation, so this sort of type pun is legal from an ABI point of view.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sometimes the old things are what you need.<\/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-104297","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Sometimes the old things are what you need.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104297","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=104297"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104297\/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=104297"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104297"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104297"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}