{"id":106540,"date":"2022-04-28T07:00:00","date_gmt":"2022-04-28T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106540"},"modified":"2022-04-28T07:20:13","modified_gmt":"2022-04-28T14:20:13","slug":"20220428-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220428-00\/?p=106540","title":{"rendered":"What&#8217;s up with <CODE>std::piecewise_construct<\/CODE> and <CODE>std::forward_as_tuple<\/CODE>?"},"content":{"rendered":"<p>There is this curious marker type in the C++ standard library called <code>piecewise_<wbr \/>construct_t<\/code>, and an inline variable <code>piecewise_<wbr \/>construct<\/code> that produces it. What&#8217;s the deal with this guy, and his friend <code>std::forward_as_tuple<\/code>?<\/p>\n<p><a href=\"https:\/\/twitter.com\/StephanTLavavej\"> STL<\/a> explained it to me.<\/p>\n<p>We&#8217;ll start with <code>std::forward_as_tuple<\/code>: This takes its arguments and produces a tuple of corresponding references.<\/p>\n<pre>int x;\r\n\r\n\/\/ produces std::tuple&lt;int&amp;, std::string&amp;&amp;&gt;\r\nstd::forward_as_tuple(x, std::string(L\"hello\"));\r\n<\/pre>\n<p>Note that this potentially contains a tuple of rvalue references, which means that you had better use the tuple before the end of the statement, before the temporaries are destroyed. If you don&#8217;t, then you have a use-after-free bug:<\/p>\n<pre>auto values = std::forward_as_tuple(x, std::string(L\"hello\"));\r\n<i>std::get&lt;1&gt;(values); \/\/ dangling reference to destructed string<\/i>\r\n<\/pre>\n<p>The purpose of <code>std::forward_as_tuple<\/code> is to wrap up a bunch of parameters, probably a parameter pack, into a single object that can be passed as a single non-pack parameter. This is handy if you need to work with a pattern that accepts only a single parameter, so you use the tuple as a way to aggregate multiple objects into one.<\/p>\n<pre>template&lt;typename...Args&gt;\r\nauto f(Args&amp;&amp;...args)\r\n{\r\n    auto t = std::forward_as_tuple(std::forward&lt;Args&gt;(args)...);\r\n    ... do something with t ...\r\n}\r\n<\/pre>\n<p>A case where you may want to wrap up a bunch of parameters into a single parameter is if you need to pass <i>multiple<\/i> groups of parameters. The C++ language doesn&#8217;t let you write<\/p>\n<pre>template&lt;typename...Group1,\r\n         typename...Group2&gt;\r\nvoid something(Group1&amp;&amp;... group1,\r\n               Group2&amp;&amp;... group2)\r\n{\r\n    ...\r\n}\r\n<\/pre>\n<p>because there&#8217;s no way to know where the first group ends and the second group begins. But you can do this if you pass the parameters as perfectly-forwarded tuples of references.<\/p>\n<pre>template&lt;typename...Group1,\r\n         typename...Group2&gt;\r\nvoid something(std::tuple&lt;Group1&amp;&amp;...&gt; group1,\r\n               std::tuple&lt;Group2&amp;&amp;...&gt; group2)\r\n{\r\n    ...\r\n}\r\n<\/pre>\n<p>This is where <code>std::piecewise_construct<\/code> enters the story.<\/p>\n<p>The <code>std::pair<\/code> wants to let you construct the components in place. The existing two-parameter constructor tries to construct the first element from the first parameter and the second element from the second parameter:<\/p>\n<pre>struct T1\r\n{\r\n    T1(int);\r\n    T1(int, std::string);\r\n};\r\n\r\nstruct T2\r\n{\r\n    T2(std::string);\r\n    T2();\r\n};\r\n\r\nauto f()\r\n{\r\n    \/\/ uses T1(a1) and T2(a2)\r\n    return std::pair&lt;T1, T2&gt;(a1, a2);\r\n}\r\n<\/pre>\n<p>If you want to use a <code>T1<\/code> or <code>T2<\/code> constructor that takes any number of parameters other than one, you can pack them into tuples, and use the marker value <code>std::piecewise_construct<\/code> to say, &#8220;Hey, like, don&#8217;t pass the tuples as-is to the constructors. Instead, unpack the tuples and invoke the constructors with the tuple elements.&#8221;<\/p>\n<pre>auto f()\r\n{\r\n    \/\/ without piecewise_construct: tries to use\r\n    \/\/      T1(std::tuple&lt;int, char const*&gt;(42, \"hello\"))\r\n    \/\/ and  T2(std::tuple&lt;&gt;())\r\n    \/\/ (neither of which works)\r\n    return std::pair&lt;T1, T2&gt;(\r\n        std::make_tuple(42, \"hello\"),\r\n        std::make_tuple());\r\n}\r\n\r\nauto f()\r\n{\r\n    \/\/ with piecewise_construct:\r\n    \/\/ uses T1(42, \"hello\")\r\n    \/\/ and  T2()\r\n    return std::pair&lt;T1, T2&gt;(\r\n        std::piecewise_construct,\r\n        std::make_tuple(42, \"hello\"),\r\n        std::make_tuple());\r\n}\r\n<\/pre>\n<p>The <code>T1<\/code> and <code>T2<\/code> are constructed in place directly into the pair, and in this case, it means that they are constructed in place directly into the return value (due to copy elision).<\/p>\n<p>Now, you could have done this without <code>std::piecewise_construct<\/code>:<\/p>\n<pre>\/\/ uses T1(42, \"hello\") with T1(T1 const&amp;)\r\n\/\/ and  T2()            with T2(T2 const&amp;)\r\nreturn std::pair&lt;T1, T2&gt;({ 42, \"hello\" }, {});\r\n<\/pre>\n<p>but this does not construct the <code>T1<\/code> and <code>T2<\/code> objects in place. It uses the <code>pair(T1 const&amp;, T2 const&amp;)<\/code> constructor. That means that it creates a temporary <code>T1(42, \"hello\")<\/code> and passes it as a <code>T1 const&amp;<\/code> to <code>T1<\/code>&#8216;s constructor, which will copy it. Similarly, it creates a temporary <code>T2()<\/code> object, and then copies the temporary to the pair&#8217;s <code>T2<\/code>.<\/p>\n<p>Not only is it wasteful, but it also requires that <code>T1<\/code> and <code>T2<\/code> be copyable, which may not be possible for the <code>T1<\/code> and <code>T2<\/code> you need.<\/p>\n<p>If your <code>T1<\/code> and <code>T2<\/code> are at least movable, you could use<\/p>\n<pre>\/\/ uses T1(42, \"hello\") with T1(T1 &amp;&amp;)\r\n\/\/ and  T2()            with T2(T2 &amp;&amp;)\r\nreturn std::pair&lt;T1, T2&gt;(T1{ 42, \"hello\" }, T2{});\r\n<\/pre>\n<p>That saves you a copy, but it&#8217;s not quite the same as just constructing in place from the original parameters.<\/p>\n<p>The <code>std::piecewise_construct<\/code> marker works well in conjunction with <code>std::forward_as_tuple<\/code>:<\/p>\n<pre>template&lt;typename...Args&gt;\r\nauto make_t1_with_default_t2(Args&amp;&amp;...args)\r\n{\r\n    return std::pair&lt;T1, T2&gt;(\r\n        std::piecewise_construct,\r\n        std::forward_as_tuple(std::forward&lt;Args&gt;(args)...),\r\n        std::make_tuple());\r\n}\r\n<\/pre>\n<p>The <code>std::piecewise_construct<\/code> marker pattern propagates into all of the <code>emplace<\/code> methods, since emplacement is built out of the constructor.<\/p>\n<pre>std::vector&lt;std::pair&lt;T1, T2&gt;&gt; v;\r\n\r\ntemplate&lt;typename...Args&gt;\r\nauto add_t1_with_default_t2(Args&amp;&amp;...args)\r\n{\r\n    v.emplace_back(\r\n        std::piecewise_construct,\r\n        std::forward_as_tuple(std::forward&lt;Args&gt;(args)...),\r\n        std::make_tuple());\r\n}\r\n<\/pre>\n<p>In particular, you&#8217;re likely to use it with <code>std::map::emplace<\/code>, since that takes a pair.<\/p>\n<pre>std::map&lt;T1, T2&gt; m;\r\n\r\nm.emplace(\r\n    std::piecewise_construct,\r\n    std::make_tuple(42, \"hello\"),\r\n    std::make_tuple());\r\n<\/pre>\n<p>Now you won&#8217;t be scared when you see <code>std::piecewise_construct<\/code>. It&#8217;s just a marker that means, &#8220;I&#8217;m going to construct multiple things, and the constructor parameters are provided as tuples, so you know where one set of parameters ends and the next one begins.&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When you need to pass two sets of variadic parameters, and to work around other extremely weird edge cases.<\/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-106540","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>When you need to pass two sets of variadic parameters, and to work around other extremely weird edge cases.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106540","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=106540"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106540\/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=106540"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106540"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106540"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}