{"id":107986,"date":"2023-03-30T07:00:00","date_gmt":"2023-03-30T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107986"},"modified":"2023-03-28T22:04:42","modified_gmt":"2023-03-29T05:04:42","slug":"20230330-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230330-00\/?p=107986","title":{"rendered":"How can I box a <CODE>std::optional<\/CODE> into a C++\/WinRT <CODE>IInspectable<\/CODE>?"},"content":{"rendered":"<p>Say you have a <code>std::optional&lt;T&gt;<\/code> in your hand, and you want to convert it to an <code>IInspectable<\/code>, say because you want to put it inside a <code>PropertySet<\/code>.<\/p>\n<pre>void SaveHeight(winrt::PropertySet const&amp; set)\r\n{\r\n    std::optional&lt;int&gt; height = GetHeight();\r\n\r\n    set.Insert(L\"height\", \/* what goes here? *\/);\r\n}\r\n<\/pre>\n<p>Well, one thing you <i>shouldn&#8217;t<\/i> do is go right for the <code>value<\/code>:<\/p>\n<pre>\/\/ Code in italics is wrong.\r\nvoid SaveHeight(winrt::PropertySet const&amp; set)\r\n{\r\n    std::optional&lt;int&gt; height = GetHeight();\r\n\r\n    set.Insert(L\"height\",\r\n        <span style=\"color: #08f;\"><i>winrt::box_value(height.value())<\/i><\/span>);\r\n}\r\n<\/pre>\n<p>Calling <code>value()<\/code> on an empty <code>std::optional<\/code> throws the <code>std::<wbr \/>bad_<wbr \/>optional_<wbr \/>access<\/code> exception. In that case, your <code>SaveHeight<\/code> method throws an exception instead of saving a <code>nullptr<\/code> into the property set. If this exception crosses an ABI boundary, C++\/WinRT and C++\/CX will convert it to <code>E_FAIL<\/code>, and WIL will convert it to <code>ERROR_<wbr \/>UNHANDLED_<wbr \/>EXCEPTION<\/code>. But really, it doesn&#8217;t matter how the C++ exception is converted to an ABI <code>HRESULT<\/code> because you didn&#8217;t want an exception in the first place. You wanted the <code>std::<wbr \/>nullopt<\/code> to convert to a null pointer.<\/p>\n<p>You could manually check for an empty <code>std::<wbr \/>optional<\/code>:<\/p>\n<pre>void SaveHeight(winrt::PropertySet const&amp; set)\r\n{\r\n    std::optional&lt;int&gt; height = GetHeight();\r\n\r\n    set.Insert(L\"height\",\r\n        <span style=\"color: #08f;\">height ? winrt::box_value(*height) : nullptr<\/span>);\r\n}\r\n<\/pre>\n<p>But there&#8217;s an even easier way.<\/p>\n<p>C++\/WinRT provides a conversion operator from <code>std::<wbr \/>optional&lt;T&gt;<\/code> to <code>IReference&lt;T&gt;<\/code> which does the obvious thing: An empty <code>std::<wbr \/>optional<\/code> becomes <code>nullptr<\/code> and a <code>std::<wbr \/>optional<\/code> with a value becomes an <code>IReference<\/code> that holds the value.<\/p>\n<pre>void SaveHeight(winrt::PropertySet const&amp; set)\r\n{\r\n    std::optional&lt;int&gt; height = GetHeight();\r\n\r\n    set.Insert(L\"height\",\r\n        <span style=\"color: #08f;\">winrt::IReference(height)<\/span>);\r\n}\r\n<\/pre>\n<p>We are taking advantage here of class template argument deduction (CTAD), which lets us write just <code>winrt::<wbr \/>IReference(...)<\/code> and let the compiler infer that we are constructing a <code>winrt::<wbr \/>IReference&lt;int&gt;<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There&#8217;s a handy conversion for that, but you have to know where to look.<\/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-107986","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>There&#8217;s a handy conversion for that, but you have to know where to look.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107986","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=107986"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107986\/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=107986"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107986"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107986"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}