{"id":106415,"date":"2022-03-30T07:00:00","date_gmt":"2022-03-30T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106415"},"modified":"2022-03-30T07:18:48","modified_gmt":"2022-03-30T14:18:48","slug":"20220330-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220330-00\/?p=106415","title":{"rendered":"Why am I getting the error message &#8220;This is only for weak ref support&#8221; when I try to create a C++\/WinRT weak reference?"},"content":{"rendered":"<p>A customer tried to obtain a weak reference from within a C++\/WinRT class implementation by calling <code>get_weak()<\/code>. This normally works, but for some reason, the customer was getting the error<\/p>\n<pre style=\"white-space: pre-wrap;\">winrt\\base.h(7594,47): error C2338: This is only for weak ref support.\r\nwinrt\\base.h(7593): message : while compiling class template member function 'winrt::impl::IWeakReferenceSource *winrt::impl::root_implements&lt;D,IWidget&gt;::make_weak_ref(void) noexcept'\r\n        with\r\n        [\r\n            D=Widget\r\n        ]\r\nwinrt\\base.h(7500): message : see reference to function template instantiation 'winrt::impl::IWeakReferenceSource *winrt::impl::root_implements&lt;D,IWidget&gt;::make_weak_ref(void) noexcept' being compiled\r\n        with\r\n        [\r\n            D=Widget\r\n        ]\r\nwinrt\\base.h(7803): message : see reference to class template instantiation 'winrt::impl::root_implements&lt;D,IWidget&gt;' being compiled\r\n        with\r\n        [\r\n            D=Widget\r\n        ]\r\nWidget.h(15): message : see reference to class template instantiation\r\n<\/pre>\n<p>The message &#8220;This is only for weak ref support&#8221; is rather enigmatic. It sounds like an internal note from the authors of the C++\/WinRT library to their future selves, telling them that they made some sort of internal error.<\/p>\n<p>But let&#8217;s see if we can figure out what it&#8217;s saying. This is another segment in the &#8220;Behind C++\/WinRT series&#8221; (and the larger topic of decoding template metaprogramming).<\/p>\n<p>The error message comes from <a href=\"https:\/\/github.com\/microsoft\/cppwinrt\/blob\/b4015649c5c658846bcd13d842a76e16135ea207\/strings\/base_implements.h#L1128\"> make_weak_ref<\/a>, which is a helper function <a href=\"https:\/\/github.com\/microsoft\/cppwinrt\/blob\/b4015649c5c658846bcd13d842a76e16135ea207\/strings\/base_implements.h#L1034\"> called from get_weak<\/a>:<\/p>\n<pre>static_assert(is_weak_ref_source::value, \"This is only for weak ref support.\");\r\n<\/pre>\n<p>What is <code>is_<wbr \/>weak_<wbr \/>ref_<wbr \/>source<\/code>? Let&#8217;s look for it:<\/p>\n<pre style=\"white-space: pre-wrap;\">using is_inspectable = std::disjunction&lt;std::is_base_of&lt;Windows::Foundation::IInspectable, I&gt;...&gt;;\r\nusing is_weak_ref_source = std::conjunction&lt;is_inspectable, std::negation&lt;std::disjunction&lt;std::is_same&lt;no_weak_ref, I&gt;...&gt;&gt;&gt;;\r\n<\/pre>\n<p>We saw in an earlier installment <a title=\"Behind C++\/WinRT: How does C++\/WinRT decide which interfaces are implemented?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220324-00\/?p=106381\"> how to read <code>std::disjunction<\/code>, <code>std:conjunction<\/code>, and <code>std::negation<\/code><\/a>.<\/p>\n<p>First, let&#8217;s untangle <code>is_<wbr \/>inspectable<\/code>: It checks each of the implemented interfaces <code>I<\/code> to see if it has <code>Windows::<wbr \/>Foundation::<wbr \/>IInspectable<\/code> as a base class, and then uses <code>std::disjunction<\/code> to &#8220;or&#8221; all the results together via a template parameter pack expansion. Therefore, <code>is_inspectable<\/code> is true if any of the implemented interfaces has <code>Windows::<wbr \/>Foundation::<wbr \/>IInspectable<\/code> as a base class, which means that at least one of the interfaces is or is derived from <code>IInspectable<\/code>.<\/p>\n<p>Next, we calculate <code>is_<wbr \/>weak_<wbr \/>ref_<wbr \/>source<\/code>. The parameter pack expansion checks whether any of the implemented interfaces is the marker type <code>no_<wbr \/>weak_<wbr \/>ref<\/code>. Therefore, through the power of <i>reading code<\/i>, we determine that in order for a type to support weak references, it must<\/p>\n<ul>\n<li>Implement <code>IInspectable<\/code>, and<\/li>\n<li>Not mention <code>no_<wbr \/>weak_<wbr \/>ref<\/code>.<\/li>\n<\/ul>\n<p>Applying our newfound knowledge, we can see from the error message that the thing being implemented is <code>root_implements&lt;Widget, IWidget&gt;<\/code>. The sole interface is <code>IWidget<\/code>, and there is no mention of <code>no_<wbr \/>weak_<wbr \/>ref<\/code>, so the force of logic compels us to conclude that <code>IWidget<\/code> must not derive from <code>IInspectable<\/code>.<\/p>\n<p>Checking with the customer confirms that <code>IWidget<\/code> is a classic COM interface and C++\/WinRT therefore does not generate weak reference support for <code>Widget<\/code>, which explains why <code>get_weak()<\/code> was producing a compiler error.<\/p>\n<p><b>Bonus chatter<\/b>: <a href=\"https:\/\/github.com\/microsoft\/cppwinrt\/pull\/1104\"> C++\/WinRT pull request 1104<\/a> removes the requirement that one of the interfaces derive from <code>IInspectable<\/code>. With that change (available in build 2.0.220224.4), everything supports weak references by default. To remove weak reference support, you say <code>no_<wbr \/>weak_<wbr \/>ref<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Reverse-engineering the error message.<\/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-106415","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Reverse-engineering the error message.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106415","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=106415"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106415\/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=106415"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106415"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106415"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}