{"id":110527,"date":"2024-11-15T07:00:00","date_gmt":"2024-11-15T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110527"},"modified":"2024-11-16T09:44:47","modified_gmt":"2024-11-16T17:44:47","slug":"20241115-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20241115-00\/?p=110527","title":{"rendered":"How do I put a non-copyable, non-movable, non-constructible object into a <CODE>std::optional<\/CODE>?"},"content":{"rendered":"<p>Last time, <a title=\"Solving the puzzle of trying to put an object into a std::optional\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20241114-00\/?p=110521\"> we wondered how you could put an object into a <code>std::<wbr \/>optional&lt;T&gt;<\/code> if <code>T<\/code> is not copyable, not movable, and not constructible<\/a>. You typically run into this case when <code>T<\/code> is an object that comes from a factory method rather than a constructor.<\/p>\n<p>For expository purposes, say we have a <code>Widget<\/code> that can be created inside a region or outside a region. One possible design would be to have a constructor that takes a <code>bool<\/code> that say whether to go inside or outside.<\/p>\n<pre>struct Widget\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">Widget(Region const&amp; region, bool inside);<\/span>\r\n\r\n    Widget(Widget const&amp;) = delete;\r\n    Widget(Widget &amp;amp&amp;) = delete;\r\n    Widget&amp; operator=(Widget const&amp;) = delete;\r\n    Widget&amp; operator=(Widget &amp;amp&amp;) = delete;\r\n};\r\n<\/pre>\n<p>I&#8217;m not a fan of this design because you have to remember what that final <code>bool<\/code> means.<\/p>\n<pre>Widget widget(region, true); \/\/ what does \"true\" mean?\r\n<\/pre>\n<p>Does that <code>true<\/code> mean &#8220;initially enabled&#8221;? Does it mean &#8220;inside&#8221;? Does it mean &#8220;outside&#8221;?<\/p>\n<p>To remove ambiguity, we can switch to factory methods.<\/p>\n<pre>struct Widget\r\n{\r\n    Widget() = delete;\r\n    Widget(Widget const&amp;) = delete;\r\n    Widget(Widget &amp;amp&amp;) = delete;\r\n    Widget&amp; operator=(Widget const&amp;) = delete;\r\n    Widget&amp; operator=(Widget &amp;amp&amp;) = delete;\r\n\r\n    static Widget CreateInside(Region const&amp; region);\r\n    static Widget CreateOutside(Region const&amp; region);\r\nprivate:\r\n    \u27e6 ... \u27e7\r\n};\r\n<\/pre>\n<p>Okay, so how can we put a <code>Widget<\/code> inside a <code>std::<wbr \/>optional&lt;Widget&gt;<\/code>? All of our tools for putting an object into an <code>optional<\/code> are failing us. We can&#8217;t use <code>emplace<\/code>: That will try to construct the <code>Widget<\/code> from the thing we passed to emplace, but <code>Widget<\/code> is not constructible!<\/p>\n<p>The trick is that the <code>std::<wbr \/>optional<\/code> constructor and assignment operator create the <code>T<\/code> as if by non-list-initialization. This means that implicit conversion operators are in play!<\/p>\n<pre>struct WidgetInsideRegionCreator\r\n{\r\n    WidgetCreator(Region const&amp; region) : m_region(region) {}\r\n    operator Widget() { return Widget::CreateInside(m_region); }\r\n    Region const&amp; m_region;\r\n};\r\n\r\nvoid sample(Region const&amp; region)\r\n{\r\n    \/\/ construct with a Widget value\r\n    std::optional&lt;Widget&gt; o(WidgetInsideRegionCreator(region));\r\n\r\n    \/\/ or place a Widget into the optional\r\n    o.emplace(WidgetInsideRegionCreator(region));\r\n}\r\n<\/pre>\n<p>The idea here is that we create a helper object, the <code>Widget\u00adInside\u00adRegion\u00adCreator<\/code>, which supports an implicit conversion to <code>Widget<\/code> via the factory method. The <code>Widget<\/code> can then be initialized from the helper object by conversion. The return value from the conversion operator is placed directly in the <code>optional<\/code>&#8216;s <code>Widget<\/code> thanks to mandatory copy elision.<\/p>\n<p>Okay, now that we know what to do, we can generalize it, so you don&#8217;t have to create dozens of tiny little creator classes.<\/p>\n<pre>template&lt;typename F&gt;\r\nstruct EmplaceHelper\r\n{\r\n    EmplaceHelper(F&amp;&amp; f) : m_f(f) {}\r\n    operator auto() { return m_f(); }\r\n    F&amp; m_f;\r\n};\r\n\r\nvoid sample(Region const&amp; region)\r\n{\r\n    \/\/ construct with a Widget value\r\n    std::optional&lt;Widget&gt; o(\r\n        EmplaceHelper([&amp;] {\r\n            return Widget::CreateInside(region);\r\n        }));\r\n\r\n    \/\/ or place a Widget into the optional\r\n    o.emplace(EmplaceHelper([&amp;] {\r\n            return Widget::CreateInside(region);\r\n        }));\r\n}\r\n<\/pre>\n<p>This trick works even if the factory method belongs to another object.<\/p>\n<pre>struct WidgetFactory\r\n{\r\n    Widget CreateInside(Region const&amp; region) const;\r\n};\r\n\r\nvoid sample(WidgetFactory const&amp; factory,\r\n            Region const&amp; region)\r\n{\r\n    \/\/ construct with a Widget value\r\n    std::optional&lt;Widget&gt; o(\r\n        EmplaceHelper([&amp;] {\r\n            return factory.CreateInside(region);\r\n        }));\r\n\r\n    \/\/ or place a Widget into the optional\r\n    o.emplace(EmplaceHelper([&amp;] {\r\n            return factory.CreateInside(region);\r\n        }));\r\n}\r\n<\/pre>\n<p>If you don&#8217;t like lambdas, you can try <a title=\"The std::invoke function does more than invoke functions\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220401-00\/?p=106426\"> invoke-oriented programming<\/a>.<\/p>\n<pre>template&lt;typename F, typename... Args&gt;\r\nstruct EmplaceHelper\r\n{\r\n    EmplaceHelper(F&amp;&amp; f, Args&amp;&amp;... args)\r\n        : m_f(f), m_args((Args&amp;&amp;)args...) {}\r\n    operator auto()\r\n        { return std::apply(m_f, m_args); }\r\n    F&amp; m_f;\r\n    std::tuple&lt;Args&amp;&amp;...&gt; m_args;\r\n};\r\n\r\ntemplate&lt;typename F, typename... Args&gt;\r\nEmplaceHelper(F&amp;&amp;, Args&amp;&amp;...) -&gt; EmplaceHelper&lt;F, Args...&gt;;\r\n\r\nvoid sample(WidgetFactory const&amp; factory,\r\n            Region const&amp; region)\r\n{\r\n    \/\/ construct with a Widget value\r\n    std::optional o(\r\n        EmplaceHelper(Widget::CreateInside, region));\r\n\r\n    \/\/ or place a Widget into the optional\r\n    o.emplace(EmplaceHelper(&amp;WidgetFactory::CreateInside,\r\n                            factory, region));\r\n\r\n    \/\/ lambdas still work\r\n    o.emplace(EmplaceHelper([&amp;] {\r\n            return factory.CreateInside(region);\r\n        }));\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Taking advantage of the conversion operator.<\/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-110527","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Taking advantage of the conversion operator.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110527","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=110527"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110527\/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=110527"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110527"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110527"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}