{"id":110893,"date":"2025-02-20T07:00:00","date_gmt":"2025-02-20T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110893"},"modified":"2025-02-20T15:02:21","modified_gmt":"2025-02-20T23:02:21","slug":"20250220-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250220-00\/?p=110893","title":{"rendered":"C++\/WinRT implementation inheritance: Notes on <CODE>winrt::implements<\/CODE>, part 2"},"content":{"rendered":"<p>Some time ago, we investigated <a title=\"Behind C++\/WinRT: How does C++\/WinRT get the list of implemented interfaces?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220325-00\/?p=106384\"> how C++\/WinRT decides which interfaces your class implements when you use the <code>implements<\/code> template<\/a>.<\/p>\n<p>I promised to talk about <code>unwrap_<wbr \/>implements_t<\/code> at some point in the future, so I guess now&#8217;s the time.<\/p>\n<pre>template &lt;typename T, typename = std::void_t&lt;&gt;&gt;\r\nstruct unwrap_implements\r\n{\r\n    using type = T;\r\n};\r\n\r\ntemplate &lt;typename T&gt;\r\nstruct unwrap_implements&lt;T,\r\n    std::void_t&lt;typename T::implements_type&gt;&gt;\r\n{\r\n    using type = typename T::implements_type;\r\n};\r\n\r\ntemplate &lt;typename T&gt;\r\nusing unwrap_implements_t =\r\n    typename unwrap_implements&lt;T&gt;::type;\r\n<\/pre>\n<p>The <code>std::<wbr \/>void_t<\/code> template is a helper for <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/sfinae\"> SFINAE<\/a>: it expands to <code>void<\/code> if all if its template arguments can be evaluated. The first usage of it is in the definition of the basic case:<\/p>\n<pre>template &lt;typename T, typename = std::void_t&lt;&gt;&gt;\r\nstruct unwrap_implements\r\n{\r\n    using type = T;\r\n};\r\n<\/pre>\n<p>Here, we use <code>std::<wbr \/>void_t&lt;&gt;<\/code>. Since all of the template arguments can be evaluated (<a title=\"Embracing the power of the empty set in API design (and applying this principle to selectors and filters)\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240812-00\/?p=110121\">all zero of them<\/a>), this is the same as just <code>void<\/code>. I&#8217;m not sure why the code uses the longer formulation instead of just writing <code>void<\/code>; maybe it&#8217;s just to parallel the usage of <code>std::<wbr \/>void_t<\/code> argument in the partial specialization.<\/p>\n<p>The partial specialization uses <code>std::<wbr \/>void_t&lt;<wbr \/>typename T::<wbr \/>implements_<wbr \/>type&gt;<\/code>, so it is testing whether the type <code>T<\/code> has a member type named <code>implements_<wbr \/>type<\/code>. If so, then this partial specialization succeeds, and the <code>type<\/code> is whatever <code>implements_<wbr \/>type<\/code> was. The <code>implements<\/code> template creates an <code>implements_<wbr \/>type<\/code> member type, so this succeeds when <code>T<\/code> derives from <code>implements<\/code> (possibly through a chain of intermediate classes).<\/p>\n<p>Therefore, the result of <code>unwrap_<wbr \/>implements&lt;<wbr \/>T&gt;::<wbr \/>type<\/code> is the <code>implements<\/code> if <code>T<\/code> derives (eventually) from <code>implements<\/code>; otherwise, it&#8217;s just <code>T<\/code> itself.<\/p>\n<p>The last part is just making <code>unwrap_<wbr \/>implements_t&lt;T&gt;<\/code> a shorthand for <code>unwrap_<wbr \/>implements&lt;T&gt;::<wbr \/>type<\/code>.<\/p>\n<p>I talked through this whole thing step by step, but after some practice, you recognize this pattern fairly quickly, and you read it as &#8220;if (SFINAE condition) then (partial specialization thing) else (fallback thing).&#8221;<\/p>\n<p>Next time, we&#8217;ll build on this to understand the allowable inheritance structures for <code>winrt::<wbr \/>implements<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Untangling <CODE>unwrap_<WBR>implements_t<\/CODE>.<\/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-110893","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Untangling <CODE>unwrap_<WBR>implements_t<\/CODE>.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110893","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=110893"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110893\/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=110893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110893"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}