{"id":103191,"date":"2019-12-06T07:00:00","date_gmt":"2019-12-06T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103191"},"modified":"2019-12-06T05:02:48","modified_gmt":"2019-12-06T13:02:48","slug":"20191206-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191206-00\/?p=103191","title":{"rendered":"In C++\/WinRT, what happens when I treat an <CODE>IInspectable<\/CODE> as or convert one to a <CODE>bool<\/CODE>"},"content":{"rendered":"<p>Last time, we looked at <a href=\"http:\/\/devblogs.microsoft.com\/oldnewthing\/20191205-00\/?p=103183\"> weirdness in how C++\/CX treats hat pointers in a <code>bool<\/code> context<\/a>. Fortunately, C++\/WinRT is much less weird.<\/p>\n<p>The <code>IInspectable<\/code> type supports a conversion to <code>bool<\/code> which tests whether the underlying pointer is null. It also supports comparison against <code>nullptr<\/code> which tests the same thing. And, unlike C++\/CX, C++\/WinRT uses this conversion for both explicit and contextual conversions.<\/p>\n<pre>IInspectable p = winrt::box_value(false);\r\nIInspectable q = winrt::box_value(false);\r\n\r\nif (p)                    std::cout &lt;&lt; 1;\r\nif ((bool)p)              std::cout &lt;&lt; 2;\r\nif (static_cast&lt;bool&gt;(p)) std::cout &lt;&lt; 3;\r\nif (p == q)               std::cout &lt;&lt; 4;\r\nif (p == false)           std::cout &lt;&lt; 5;\r\nif (!p)                   std::cout &lt;&lt; 6;\r\nif ((bool)p == (bool)q)   std::cout &lt;&lt; 7;\r\n<\/pre>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th>Condition<\/th>\n<th>What&#8217;s happening<\/th>\n<th>Result<\/th>\n<\/tr>\n<tr>\n<td><tt>if (p)<\/tt><\/td>\n<td>Tests <tt>p<\/tt> against <tt>nullptr<\/tt>.<\/td>\n<td>prints <tt>1<\/tt><\/td>\n<\/tr>\n<tr>\n<td><tt>if ((bool)p)<\/tt><\/td>\n<td>Tests <tt>p<\/tt> against <tt>nullptr<\/tt>.<\/td>\n<td>prints <tt>2<\/tt><\/td>\n<\/tr>\n<tr>\n<td><tt>if (static_cast&lt;bool&gt;(p))<\/tt><\/td>\n<td>Tests <tt>p<\/tt> against <tt>nullptr<\/tt>.<\/td>\n<td>prints <tt>3<\/tt><\/td>\n<\/tr>\n<tr>\n<td><tt>if (p == q)<\/tt><\/td>\n<td>Compares two objects for identity.<\/td>\n<td>does not print<\/td>\n<\/tr>\n<tr>\n<td><tt>if (p == false)<\/tt><\/td>\n<td colspan=\"2\">Not allowed (compiler error).<\/td>\n<\/tr>\n<tr>\n<td><tt>if (!p)<\/tt><\/td>\n<td>Tests <tt>p<\/tt> against <tt>nullptr<\/tt>.<\/td>\n<td>does not print<\/td>\n<\/tr>\n<tr>\n<td><tt>if ((bool)p == (bool)q)<\/tt><\/td>\n<td>Tests <tt>p<\/tt> and <tt>q<\/tt> against <tt>nullptr<\/tt>.<\/td>\n<td>prints 7<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Note that the last case prints <tt>7<\/tt> but not for the reason you think. It&#8217;s not doing any unboxing at all. It&#8217;s just checking whether both variables are non-null.<\/p>\n<pre>IInspectable t = winrt::box_value(true);\r\nif ((bool)p == (bool)t)   std::cout &lt;&lt; 8; \/\/ prints 8!\r\n<\/pre>\n<p><b>Bonus chatter<\/b>: There is a little quirk in the <code>p == false<\/code> case. My understanding is that prior to C++11, <code>false<\/code> was a legal <i>null pointer constant<\/i>, but the rules in C++11 were tightened so that <code>false<\/code> is no longer a null pointer context.<\/p>\n<p>Microsoft&#8217;s Visual Studio C++ compiler, however, continues to accept <code>false<\/code> as a null pointer constant, even in non-permissive mode. This means that if you&#8217;re using Microsoft&#8217;s Visual Studio C++ compiler, the fifth row of the table is slightly different:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th>Condition<\/th>\n<th>What&#8217;s happening<\/th>\n<th>Result<\/th>\n<\/tr>\n<tr>\n<td><tt>if (p == false)<\/tt><\/td>\n<td><code>false<\/code> converted to <code>IInspectable{ nullptr }<\/code> <br \/>\nand compared with <code>p<\/code><\/td>\n<td>does not print<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Much less weird than C++\/CX.<\/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-103191","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Much less weird than C++\/CX.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103191","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=103191"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103191\/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=103191"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103191"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103191"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}