{"id":108494,"date":"2023-07-27T07:00:00","date_gmt":"2023-07-27T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108494"},"modified":"2023-07-27T07:02:43","modified_gmt":"2023-07-27T14:02:43","slug":"20230727-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230727-00\/?p=108494","title":{"rendered":"Perfect forwarding forwards objects, not braced things that are trying to become objects"},"content":{"rendered":"<p>In C++, perfect forwarding is the act of passing a function&#8217;s parameters to another function while preserving its reference category. It is commonly used by wrapper methods that want to pass their parameters through to another function, often a constructor.<\/p>\n<pre>template&lt;typename T, typename... Args&gt;\r\nstd::unique_ptr&lt;T&gt; make_unique(Args&amp;&amp;... args)\r\n{\r\n    return std::unique_ptr&lt;T&gt;(\r\n        new T(std::forward&lt;Args&gt;(args)...));\r\n}\r\n<\/pre>\n<p>The <code>make_unique<\/code> function takes its parameters, forwards them to the <code>T<\/code> constructor, and then puts the pointer to the newly-constructed <code>T<\/code> inside a <code>unique_ptr<\/code>. Those parameters are forwarded perfectly into the constructor: If the original parameters were rvalue reference, then the constructor receives rvalue reference. If the original parameters were lvalue references, then the constructor receives lvalue reference.<\/p>\n<p>But the catch is that it can forward only <i>objects<\/i>. It can&#8217;t forward &#8220;braced things that are trying to become objects&#8221;.<\/p>\n<pre>struct Point\r\n{\r\n    int x, y;\r\n};\r\n\r\nstruct Segment\r\n{\r\n    Segment(Point p1, Point p2);\r\n};\r\n\r\nvoid test()\r\n{\r\n    \/\/ This works\r\n    Segment s({ 1, 1 }, { 2, 2 });\r\n\r\n    \/\/ This doesn't\r\n    auto p = std::make_unique&lt;Segment&gt;(\r\n        { 1, 1 }, { 2, 2 });\r\n}\r\n<\/pre>\n<p>The constructor of <code>Segment<\/code> says that it wants two <code>Point<\/code>s, and if you pass some stuff enclosed in braces, the compiler knows, &#8220;Well, I should make a <code>Point<\/code> out of this.&#8221;<\/p>\n<p>On the other hand, the parameters to <code>make_<wbr \/>unique<\/code> are generic and are eventually forwarded to the constructor. But at the time the compiler sees the call to <code>std::<wbr \/>make_unique<\/code>, all it sees is a bunch of stuff inside curly braces.<\/p>\n<p>And a bunch of stuff inside curly braces is not an object.\u00b9 It&#8217;s a thing that can help initialize an object, but it&#8217;s not itself an object. It has no type, and it cannot be stored in a variable or parameter. I mean, we know by our powers of clairvoyance that the stuff inside curly braces is eventually going to be used to construct a <code>Point<\/code>, and that <code>make_<wbr \/>unique<\/code> doesn&#8217;t ever do anything that needs to know its type; it doesn&#8217;t do <code>decltype(arg1)<\/code> or <code>auto arg1_copy = arg1;<\/code>.<\/p>\n<p>We know that because we read ahead and saw what the <code>make_unique<\/code> function does with the parameters. But the compiler doesn&#8217;t look that far ahead.\u00b2<\/p>\n<p>Perfect forwarding is not perfect.<\/p>\n<p>You can work around this by providing your own wrappers that accept the same parameters as the constructors. Since these parameters have types, the compiler knows what &#8220;things inside braces&#8221; are supposed to be.<\/p>\n<pre>struct Segment\r\n{\r\n    Segment(Point p1, Point p2);\r\n\r\n    static std::unique_ptr&lt;Segment&gt; make_unique(\r\n        Point p1, Point p2)\r\n    {\r\n        return std::make_unique&lt;Segment&gt;(p1, p2);\r\n    }\r\n};\r\n<\/pre>\n<p>Now, we are kind of cheating here because we are copying the <code>Point<\/code> objects all over the place. We get away with it because a <code>Point<\/code> is a very lightweight class. On the other hand, if it were more expensive (or even impossible) to copy a <code>Point<\/code>, we could accept a reference and forward it. This time, we can use a forwarding reference, but give the template types a <i>hint<\/i>:<\/p>\n<pre>struct Segment\r\n{\r\n    Segment(Point p1, Point p2);\r\n\r\n    template&lt;typename Arg1 = Point,\r\n             typename Arg2 = Point&gt;\r\n    static std::unique_ptr&lt;Segment&gt; make_unique(\r\n        Arg1&amp;&amp; p1, Arg2&amp;&amp; p2)\r\n    {\r\n        return std::make_unique&lt;Segment&gt;(\r\n            std::forward&lt;Arg1&gt;(p1),\r\n            std::forward&lt;Arg2&gt;(p2));\r\n    }\r\n};\r\n<\/pre>\n<p>This accepts anything for the two parameters and forwards them perfectly to <code>std::<wbr \/>make_unique<\/code>. Providing defaults for the <code>Arg1<\/code> and <code>Arg2<\/code> template type parameters tells the compiler, &#8220;And if you can&#8217;t figure out what type it is, try this.&#8221; That way, if the caller passes a bunch of junk inside curly braces, the compiler will try to use it to construct a <code>Point<\/code>.<\/p>\n<p>\u00b9 Okay, it might become an <code>initializer_list<\/code>, but that comes later.<\/p>\n<p>\u00b2 And in the case where the function being called is visible only as a prototype, the compiler couldn&#8217;t look into the body even if it wanted to.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Before you can forward something, it needs to be a something.<\/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-108494","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Before you can forward something, it needs to be a something.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108494","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=108494"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108494\/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=108494"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108494"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108494"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}